mirror of
https://github.com/openjdk/jdk.git
synced 2026-06-08 11:35:21 +00:00
8005403: Open-source Nashorn
Co-authored-by: Akhil Arora <akhil.arora@oracle.com> Co-authored-by: Andreas Woess <andreas.woess@jku.at> Co-authored-by: Attila Szegedi <attila.szegedi@oracle.com> Co-authored-by: Hannes Wallnoefer <hannes.wallnoefer@oracle.com> Co-authored-by: Henry Jen <henry.jen@oracle.com> Co-authored-by: Marcus Lagergren <marcus.lagergren@oracle.com> Co-authored-by: Pavel Semenov <pavel.semenov@oracle.com> Co-authored-by: Pavel Stepanov <pavel.stepanov@oracle.com> Co-authored-by: Petr Hejl <petr.hejl@oracle.com> Co-authored-by: Petr Pisl <petr.pisl@oracle.com> Co-authored-by: Sundararajan Athijegannathan <sundararajan.athijegannathan@oracle.com> Reviewed-by: attila, hannesw, lagergren, sundar
This commit is contained in:
parent
958099576a
commit
98762d6ee0
@ -1,4 +1,25 @@
|
||||
syntax: glob
|
||||
|
||||
^build/
|
||||
^dist/
|
||||
/nbproject/private/
|
||||
^.hgtip
|
||||
/nbproject/private/
|
||||
^webrev/
|
||||
webrev.zip
|
||||
*.class
|
||||
*.log
|
||||
*.orig
|
||||
hotspot.log
|
||||
private.properties
|
||||
genfiles.properties
|
||||
private.xml
|
||||
.DS_Store*
|
||||
TEST-*.xml
|
||||
TESTS-*.xml
|
||||
report.xml
|
||||
CC/
|
||||
jcov2/
|
||||
buildtools/nasgen/nbproject/private/
|
||||
buildtools/nasgen/dist/
|
||||
buildtools/nasgen/build/
|
||||
.idea/*
|
||||
|
||||
27
nashorn/ASSEMBLY_EXCEPTION
Normal file
27
nashorn/ASSEMBLY_EXCEPTION
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
OPENJDK ASSEMBLY EXCEPTION
|
||||
|
||||
The OpenJDK source code made available by Sun at openjdk.java.net and
|
||||
openjdk.dev.java.net ("OpenJDK Code") is distributed under the terms of the
|
||||
GNU General Public License <http://www.gnu.org/copyleft/gpl.html> version 2
|
||||
only ("GPL2"), with the following clarification and special exception.
|
||||
|
||||
Linking this OpenJDK Code statically or dynamically with other code
|
||||
is making a combined work based on this library. Thus, the terms
|
||||
and conditions of GPL2 cover the whole combination.
|
||||
|
||||
As a special exception, Sun gives you permission to link this
|
||||
OpenJDK Code with certain code licensed by Sun as indicated at
|
||||
http://openjdk.java.net/legal/exception-modules-2007-05-08.html
|
||||
("Designated Exception Modules") to produce an executable,
|
||||
regardless of the license terms of the Designated Exception Modules,
|
||||
and to copy and distribute the resulting executable under GPL2,
|
||||
provided that the Designated Exception Modules continue to be
|
||||
governed by the licenses under which they were offered by Sun.
|
||||
|
||||
As such, it allows licensees and sublicensees of Sun's GPL2 OpenJDK Code to
|
||||
build an executable that includes those portions of necessary code that Sun
|
||||
could not provide under GPL2 (or that Sun has provided under GPL2 with the
|
||||
Classpath exception). If you modify or add to the OpenJDK code, that new
|
||||
GPL2 code may still be combined with Designated Exception Modules if the
|
||||
new code is made subject to this exception by its copyright holder.
|
||||
347
nashorn/LICENSE
Normal file
347
nashorn/LICENSE
Normal file
@ -0,0 +1,347 @@
|
||||
The GNU General Public License (GPL)
|
||||
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license
|
||||
document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom to share
|
||||
and change it. By contrast, the GNU General Public License is intended to
|
||||
guarantee your freedom to share and change free software--to make sure the
|
||||
software is free for all its users. This General Public License applies to
|
||||
most of the Free Software Foundation's software and to any other program whose
|
||||
authors commit to using it. (Some other Free Software Foundation software is
|
||||
covered by the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, 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 or use pieces of it in new free programs; and that you know you
|
||||
can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid anyone to deny
|
||||
you these rights or to ask you to surrender the rights. These restrictions
|
||||
translate to certain responsibilities for you if you distribute copies of the
|
||||
software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or for
|
||||
a fee, you must give the recipients all the rights that you have. You must
|
||||
make sure that they, too, receive or can get the source code. And you must
|
||||
show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and (2)
|
||||
offer you this license which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain that
|
||||
everyone understands that there is no warranty for this free software. If the
|
||||
software is modified by someone else and passed on, we want its recipients to
|
||||
know that what they have is not the original, so that any problems introduced
|
||||
by others will not reflect on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software patents. We
|
||||
wish to avoid the danger that redistributors of a free program will
|
||||
individually obtain patent licenses, in effect making the program proprietary.
|
||||
To prevent this, we have made it clear that any patent must be licensed for
|
||||
everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification
|
||||
follow.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains a notice
|
||||
placed by the copyright holder saying it may be distributed under the terms of
|
||||
this General Public License. The "Program", below, refers to any such program
|
||||
or work, and a "work based on the Program" means either the Program or any
|
||||
derivative work under copyright law: that is to say, a work containing the
|
||||
Program or a portion of it, either verbatim or with modifications and/or
|
||||
translated into another language. (Hereinafter, translation is included
|
||||
without limitation in the term "modification".) Each licensee is addressed as
|
||||
"you".
|
||||
|
||||
Activities other than copying, distribution and modification are not covered by
|
||||
this License; they are outside its scope. The act of running the Program is
|
||||
not restricted, and the output from the Program is covered only if its contents
|
||||
constitute a work based on the Program (independent of having been made by
|
||||
running the Program). Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's 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 give any other recipients of the
|
||||
Program a copy of this License along with the Program.
|
||||
|
||||
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 Program or any portion of it, thus
|
||||
forming a work based on the Program, 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) You must cause the modified files to carry prominent notices stating
|
||||
that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in whole or
|
||||
in part contains or is derived from the Program or any part thereof, to be
|
||||
licensed as a whole at no charge to all third parties under the terms of
|
||||
this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively when run,
|
||||
you must cause it, when started running for such interactive use in the
|
||||
most ordinary way, to print or display an announcement including an
|
||||
appropriate copyright notice and a notice that there is no warranty (or
|
||||
else, saying that you provide a warranty) and that users may redistribute
|
||||
the program under these conditions, and telling the user how to view a copy
|
||||
of this License. (Exception: if the Program itself is interactive but does
|
||||
not normally print such an announcement, your work based on the Program is
|
||||
not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If identifiable
|
||||
sections of that work are not derived from the Program, 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 Program, 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 Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program with the
|
||||
Program (or with a work based on the Program) on a volume of a storage or
|
||||
distribution medium does not bring the other work under the scope of this
|
||||
License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, under
|
||||
Section 2) in object code or executable form under the terms of Sections 1 and
|
||||
2 above provided that you also do one of the following:
|
||||
|
||||
a) 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; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three years, to
|
||||
give any third party, for a charge no more than your cost of physically
|
||||
performing source distribution, a complete machine-readable copy of the
|
||||
corresponding source code, to be distributed under the terms of Sections 1
|
||||
and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer to
|
||||
distribute corresponding source code. (This alternative is allowed only
|
||||
for noncommercial distribution and only if you received the program in
|
||||
object code or executable form with such an offer, in accord with
|
||||
Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for making
|
||||
modifications to it. For an executable work, 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 executable. However, as a special exception, the source code
|
||||
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.
|
||||
|
||||
If distribution of executable or 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 counts as distribution of the source code, even though
|
||||
third parties are not compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program except as
|
||||
expressly provided under this License. Any attempt otherwise to copy, modify,
|
||||
sublicense or distribute the Program 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.
|
||||
|
||||
5. 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 Program
|
||||
or its derivative works. These actions are prohibited by law if you do not
|
||||
accept this License. Therefore, by modifying or distributing the Program (or
|
||||
any work based on the Program), you indicate your acceptance of this License to
|
||||
do so, and all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the Program),
|
||||
the recipient automatically receives a license from the original licensor to
|
||||
copy, distribute or modify the Program 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 to this License.
|
||||
|
||||
7. 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 Program at all.
|
||||
For example, if a patent license would not permit royalty-free redistribution
|
||||
of the Program 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 Program.
|
||||
|
||||
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.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in certain
|
||||
countries either by patents or by copyrighted interfaces, the original
|
||||
copyright holder who places the Program 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.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions of the
|
||||
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 Program
|
||||
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 Program does not specify a version number of this License, you may
|
||||
choose any version ever published by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free programs
|
||||
whose distribution conditions are different, 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
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
|
||||
THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
|
||||
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
|
||||
PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
|
||||
YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
12. 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
|
||||
PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 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 Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible
|
||||
use to the public, the best way to achieve this is to make it free software
|
||||
which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.
|
||||
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be 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; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this when it
|
||||
starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
|
||||
with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free
|
||||
software, and you are welcome to redistribute it under certain conditions;
|
||||
type 'show c' for details.
|
||||
|
||||
The hypothetical commands 'show w' and 'show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may be
|
||||
called something other than 'show w' and 'show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary. Here
|
||||
is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
'Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
signature of Ty Coon, 1 April 1989
|
||||
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General Public
|
||||
License instead of this License.
|
||||
|
||||
|
||||
"CLASSPATH" EXCEPTION TO THE GPL
|
||||
|
||||
Certain source files distributed by Oracle America and/or its affiliates are
|
||||
subject to the following clarification and special exception to the GPL, but
|
||||
only where Oracle has expressly included in the particular source file's header
|
||||
the words "Oracle designates this particular file as subject to the "Classpath"
|
||||
exception as provided by Oracle in the LICENSE file that accompanied this code."
|
||||
|
||||
Linking this library statically or dynamically with other modules is making
|
||||
a combined work based on this library. Thus, the terms and conditions of
|
||||
the GNU General Public License cover the whole combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent modules,
|
||||
and to copy and distribute the resulting executable under terms of your
|
||||
choice, provided that you also meet, for each linked independent module,
|
||||
the terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library. If
|
||||
you modify this library, you may extend this exception to your version of
|
||||
the library, but you are not obligated to do so. If you do not wish to do
|
||||
so, delete this exception statement from your version.
|
||||
147
nashorn/README
Normal file
147
nashorn/README
Normal file
@ -0,0 +1,147 @@
|
||||
- What is Nashorn?
|
||||
|
||||
Nashorn is a runtime environment for programs written in ECMAScript 5.1
|
||||
that runs on top of JVM.
|
||||
|
||||
- How to find out more about ECMAScript 5.1?
|
||||
|
||||
The specification can be found at
|
||||
|
||||
http://www.ecma-international.org/publications/standards/Ecma-262.htm
|
||||
|
||||
- How to checkout sources of Nashorn project?
|
||||
|
||||
Nashorn project uses Mercurial source code control system. You can
|
||||
download Mercurial from http://mercurial.selenic.com/wiki/Download
|
||||
|
||||
Information about the forest extension can be found at
|
||||
|
||||
http://mercurial.selenic.com/wiki/ForestExtension
|
||||
|
||||
and downlaoded using
|
||||
|
||||
hg clone https://bitbucket.org/gxti/hgforest
|
||||
|
||||
You can clone Nashorn Mercurial forest using this command:
|
||||
|
||||
hg fclone http://hg.openjdk.java.net/nashorn/jdk8 nashorn~jdk8
|
||||
|
||||
To update your copy of the forest (fwith the latest code:
|
||||
|
||||
(cd nashorn~jdk8 ; hg fpull)
|
||||
|
||||
Or just the nashorn subdirectory with
|
||||
|
||||
(cd nashorn~jdk8/nashorn ; hg pull -u)
|
||||
|
||||
To learn about Mercurial in detail, please visit http://hgbook.red-bean.com.
|
||||
|
||||
- How to build?
|
||||
|
||||
To build Nashorn, you need to install JDK 8. You may use the Nashorn
|
||||
forest build (recommended) or down load from java.net. You will need to
|
||||
set JAVA_HOME environmental variable to point to your JDK installation
|
||||
directory.
|
||||
|
||||
cd nashorn~jdk8/nashorn/make
|
||||
ant clean; ant
|
||||
|
||||
- How to run?
|
||||
|
||||
Use the jjs script (see RELESE_README):
|
||||
|
||||
cd nashorn~jdk8/nashorn
|
||||
sh bin/jjs <your .js file>
|
||||
|
||||
Nashorn supports javax.script API. It is possible to drop nashorn.jar in
|
||||
class path and request for "nashorn" script engine from
|
||||
javax.script.ScriptEngineManager.
|
||||
|
||||
Look for samples under the directory test/src/jdk/nashorn/api/scripting/.
|
||||
|
||||
- Documentation
|
||||
|
||||
Comprehensive development documentation is found in the Nashorn JavaDoc. You can
|
||||
build it using:
|
||||
|
||||
cd nashorn~jdk8/nashorn/make
|
||||
ant javadoc
|
||||
|
||||
after which you can view the generated documentation at dist/javadoc/index.html.
|
||||
|
||||
- Running tests
|
||||
|
||||
Nashorn tests are TestNG based. Running tests requires downloading the
|
||||
TestNG library and placing its jar file into the lib subdirectory:
|
||||
|
||||
# download and install TestNG
|
||||
wget http://testng.org/testng-x.y.z.zip
|
||||
unzip testng-x.y.z.zip
|
||||
cp testng-x.y.z/testng-x.y.z.jar test/lib/testng.jar
|
||||
|
||||
After that, you can run the tests using:
|
||||
cd make
|
||||
ant test
|
||||
|
||||
You can also run the ECMA-262 test suite with Nashorn. In order to do
|
||||
that, you will need to get a copy of it and put it in
|
||||
test/script/external/test262 directory. A convenient way to do it is:
|
||||
|
||||
hg clone http://hg.ecmascript.org/tests/test262/ test/script/external/test262
|
||||
|
||||
Alternatively, you can check it out elsewhere and make
|
||||
test/script/external/test262 a symbolic link to that directory. After
|
||||
you've done this, you can run the ECMA-262 tests using:
|
||||
|
||||
cd nashorn~jdk8/nashorn/make
|
||||
ant test262
|
||||
|
||||
These tests take time, so we have a parallelized runner for them that
|
||||
takes advantage of all processor cores on the computer:
|
||||
|
||||
cd nashorn~jdk8/nashorn/make
|
||||
ant test262parallel
|
||||
|
||||
- How to write your own test?
|
||||
|
||||
Nashorn uses it's own simple test framework. Any .js file dropped under
|
||||
nashorn/test directory is considered as a test. A test file can
|
||||
optionally have .js.EXPECTED (foo.js.EXPECTED for foo.js) associated
|
||||
with it. The .EXPECTED file, if exists, should contain the output
|
||||
expected from compiling and/or running the test file.
|
||||
|
||||
The test runner crawls these directories for .js files and looks for
|
||||
JTReg-style @foo comments to identify tests.
|
||||
|
||||
* @test - A test is tagged with @test.
|
||||
|
||||
* @test/fail - Tests that are supposed to fail (compiling, see @run/fail
|
||||
for runtime) are tagged with @test/fail.
|
||||
|
||||
* @test/compile-error - Test expects compilation to fail, compares
|
||||
output.
|
||||
|
||||
* @test/warning - Test expects compiler warnings, compares output.
|
||||
|
||||
* @test/nocompare - Test expects to compile [and/or run?]
|
||||
successfully(may be warnings), does not compare output.
|
||||
|
||||
* @subtest - denotes necessary file for a main test file; itself is not
|
||||
a test.
|
||||
|
||||
* @run - A test that should be run is also tagged with @run (otherwise
|
||||
the test runner only compiles the test).
|
||||
|
||||
* @run/fail - A test that should compile but fail with a runtime error.
|
||||
|
||||
* @run/ignore-std-error - script may produce output on stderr, ignore
|
||||
this output.
|
||||
|
||||
* @argument - pass an argument to script.
|
||||
|
||||
* @option \ - pass option to engine, sample.
|
||||
|
||||
/**
|
||||
* @option --dump-ir-graph
|
||||
* @test
|
||||
*/
|
||||
20
nashorn/RELEASE_README
Normal file
20
nashorn/RELEASE_README
Normal file
@ -0,0 +1,20 @@
|
||||
The Nashorn repo is in the process of being migrated to OpenJDK and as such is
|
||||
incomplete in several areas.
|
||||
|
||||
- The build system is not fully integrated. When complete, Nashorn will be
|
||||
installed in its proper location in the JRE.
|
||||
|
||||
- Once integrated, the correct version of the JDK will be wrapped around
|
||||
Nashorn. In the meantime, ensure you use JDK8 b68 or later.
|
||||
|
||||
- The jjs tool has not been implemented in binary form yet. Use "sh bin/jjs"
|
||||
(or bin/jjs.bat on windows) in the interm.
|
||||
|
||||
- The Dynalink component is not fully integrated into Nashorn as yet, but will
|
||||
be when details are finalized.
|
||||
|
||||
- And, finally Nashorn is still in development. To stay up to date, subscribe
|
||||
to nashorn-dev@openjdk.java.net at
|
||||
|
||||
http://mail.openjdk.java.net/mailman/listinfo/nashorn-dev.
|
||||
|
||||
69
nashorn/THIRD_PARTY_README
Normal file
69
nashorn/THIRD_PARTY_README
Normal file
@ -0,0 +1,69 @@
|
||||
DO NOT TRANSLATE OR LOCALIZE.
|
||||
-----------------------------
|
||||
|
||||
%% This notice is provided with respect to ECMAScript Language
|
||||
Specification ECMA-262 Edition 5.1 which is included with the Nashorn
|
||||
technology.
|
||||
|
||||
--- 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 ---
|
||||
266
nashorn/bin/checkintest.sh
Normal file
266
nashorn/bin/checkintest.sh
Normal file
@ -0,0 +1,266 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
#best pass rate at test 262 known
|
||||
TEST262_PASS_AT_LEAST=435
|
||||
|
||||
RUN_TEST="true"
|
||||
RUN_TEST262="true"
|
||||
RUN_NODE="true"
|
||||
KEEP_OUTPUT="true"
|
||||
CLEAN_AND_BUILD_NASHORN="true"
|
||||
|
||||
#the stable node version to sync against
|
||||
NODE_LAST_STABLE=v0.6.18
|
||||
|
||||
#parse args
|
||||
for arg in $*
|
||||
do
|
||||
if [ $arg = "--no-test" ]; then
|
||||
RUN_TEST="false"
|
||||
echo "**** WARNING - you have disabled 'ant test', which is a minimum checkin requirement..."
|
||||
elif [ $arg = "--no-262" ]; then
|
||||
RUN_TEST262="false"
|
||||
elif [ $arg = "--no-node" ]; then
|
||||
RUN_NODE="false"
|
||||
elif [ $arg = "--no-build" ]; then
|
||||
CLEAN_AND_BUILD_NASHORN="false"
|
||||
elif [ $arg = "--no-logs" ]; then
|
||||
KEEP_OUTPUT="false"
|
||||
fi
|
||||
done
|
||||
|
||||
function lastpart() {
|
||||
arr=$(echo $1 | tr "/" "\n")
|
||||
for x in $arr
|
||||
do
|
||||
_last=$x
|
||||
done
|
||||
echo $_last
|
||||
}
|
||||
|
||||
function check_installed() {
|
||||
which $1 >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error $1 not installed: $?"
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
check_installed hg
|
||||
check_installed git
|
||||
check_installed mv
|
||||
check_installed git
|
||||
|
||||
PWD=$(pwd);
|
||||
|
||||
while [ -z $NASHORN_ROOT ]
|
||||
do
|
||||
if [ -e $PWD/.hg ]; then
|
||||
NASHORN_ROOT=${PWD}
|
||||
break
|
||||
fi
|
||||
PWD=$(dirname ${PWD})
|
||||
done
|
||||
|
||||
echo "Nashorn root detected at ${NASHORN_ROOT}"
|
||||
|
||||
COMMON_ROOT=$(dirname $NASHORN_ROOT)
|
||||
echo "Common root is ${COMMON_ROOT}"
|
||||
|
||||
echo "Running checkintest..."
|
||||
|
||||
ABSOLUTE_NASHORN_HOME=$COMMON_ROOT/$(lastpart $NASHORN_ROOT)
|
||||
|
||||
if [ $CLEAN_AND_BUILD_NASHORN != "false" ]; then
|
||||
echo "Cleaning and building nashorn at $ABSOLUTE_NASHORN_HOME/nashorn..."
|
||||
$(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant clean >/dev/null 2>/dev/null)
|
||||
$(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant jar >/dev/null 2>/dev/null)
|
||||
echo "Done."
|
||||
fi
|
||||
|
||||
function failure_check() {
|
||||
while read line
|
||||
do
|
||||
LINE=$(echo $line | grep "Tests run")
|
||||
if [ "${LINE}" != "" ]; then
|
||||
RESULT=$(echo $line | grep "Failures: 0" | grep "Errors: 0")
|
||||
if [ "${RESULT}" == "" ]; then
|
||||
TESTNAME=$2
|
||||
echo "There were errors in ${TESTNAME} : ${LINE}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done < $1
|
||||
}
|
||||
|
||||
function test() {
|
||||
TEST_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX)
|
||||
echo "Running 'ant test' on nashorn from ${ABSOLUTE_NASHORN_HOME}/nashorn..."
|
||||
$(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant test >$TEST_OUTPUT)
|
||||
echo "Done."
|
||||
|
||||
failure_check $TEST_OUTPUT
|
||||
|
||||
echo "**** SUCCESS: 'ant test' successful"
|
||||
|
||||
if [ $KEEP_OUTPUT == "true" ]; then
|
||||
cp $TEST_OUTPUT ./checkintest.test.log
|
||||
rm -fr $TEST_OUTPUT
|
||||
fi
|
||||
}
|
||||
|
||||
if [ $RUN_TEST != "false" ]; then
|
||||
test;
|
||||
fi
|
||||
|
||||
function test262() {
|
||||
|
||||
echo "Running 'ant test262parallel' on nashorn from ${ABSOLUTE_NASHORN_HOME}/nashorn..."
|
||||
TEST262_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX)
|
||||
|
||||
echo "Looking for ${ABSOLUTE_NASHORN_HOME}/test/test262..."
|
||||
|
||||
if [ ! -e $ABSOLUTE_NASHORN_HOME/nashorn/test/test262 ]; then
|
||||
echo "test262 is missing... looking in $COMMON_ROOT..."
|
||||
if [ ! -e $COMMON_ROOT/test262 ]; then
|
||||
echo "... not there either... cloning from repo..."
|
||||
hg clone http://hg.ecmascript.org/tests/test262 $COMMON_ROOT/test262 >/dev/null 2>/dev/null
|
||||
echo "Done."
|
||||
fi
|
||||
echo "Adding soft link ${COMMON_ROOT}/test262 -> ${ABSOLUTE_NASHORN_HOME}/test/test262..."
|
||||
ln -s $COMMON_ROOT/test262 $ABSOLUTE_NASHORN_HOME/nashorn/test/test262
|
||||
echo "Done."
|
||||
fi
|
||||
|
||||
echo "Ensuring test262 is up to date..."
|
||||
$(cd $ABSOLUTE_NASHORN_HOME/nashorn/test/test262; hg pull -u >/dev/null 2>/dev/null)
|
||||
echo "Done."
|
||||
|
||||
echo "Running test262..."
|
||||
$(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant test262parallel > $TEST262_OUTPUT)
|
||||
|
||||
FAILED=$(cat $TEST262_OUTPUT|grep "Tests run:"| cut -d ' ' -f 15 |tr -cd '"[[:digit:]]')
|
||||
if [ $FAILED -gt $TEST262_PASS_AT_LEAST ]; then
|
||||
echo "FAILURE: There are ${FAILED} failures in test262 and can be no more than ${TEST262_PASS_AT_LEAST}"
|
||||
cp $TEST262_OUTPUT ./checkintest.test262.log
|
||||
echo "See ./checkintest.test262.log"
|
||||
echo "Terminating due to error"
|
||||
exit 1
|
||||
elif [ $FAILED -lt $TEST262_PASS_AT_LEAST ]; then
|
||||
echo "There seem to have been fixes to 262. ${FAILED} < ${TEST262_PASS_AT_LEAST}. Please update limit in bin/checkintest.sh"
|
||||
fi
|
||||
|
||||
echo "**** SUCCESS: Test262 passed with no more than ${TEST262_PASS_AT_LEAST} failures."
|
||||
|
||||
if [ $KEEP_OUTPUT == "true" ]; then
|
||||
cp $TEST262_OUTPUT ./checkintest.test262.log
|
||||
rm -fr $TEST262_OUTPUT
|
||||
fi
|
||||
}
|
||||
|
||||
if [ $RUN_TEST262 != "false" ]; then
|
||||
test262;
|
||||
fi;
|
||||
|
||||
function testnode() {
|
||||
TESTNODEJAR_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX)
|
||||
|
||||
echo "Running node tests..."
|
||||
#replace node jar properties nashorn with this nashorn
|
||||
|
||||
NODEJAR_PROPERTIES=~/nodejar.properties
|
||||
|
||||
NODE_HOME=$(cat $NODEJAR_PROPERTIES | grep ^node.home | cut -f2 -d=)
|
||||
NASHORN_HOME=$(cat $NODEJAR_PROPERTIES | grep ^nashorn.home | cut -f2 -d=)
|
||||
|
||||
ABSOLUTE_NODE_HOME=$COMMON_ROOT/$(lastpart $NODE_HOME)
|
||||
|
||||
echo "Writing nodejar.properties..."
|
||||
|
||||
cat > $NODEJAR_PROPERTIES << EOF
|
||||
node.home=../node
|
||||
nashorn.home=../$(lastpart $NASHORN_ROOT)
|
||||
EOF
|
||||
echo "Done."
|
||||
echo "Checking node home ${ABSOLUTE_NODE_HOME}..."
|
||||
|
||||
if [ ! -e $ABSOLUTE_NODE_HOME ]; then
|
||||
echo "Node base dir not found. Cloning node..."
|
||||
$(cd $COMMON_ROOT; git clone https://github.com/joyent/node.git $(lastpart $NODE_HOME) >/dev/null 2>/dev/null)
|
||||
echo "Done."
|
||||
echo "Updating to last stable version ${NODE_LAST_STABLE}..."
|
||||
$(cd $ABSOLUTE_NODE_HOME; git checkout $NODE_LAST_STABLE >/dev/null 2>/dev/null)
|
||||
echo "Done."
|
||||
echo "Running configure..."
|
||||
$(cd $ABSOLUTE_NODE_HOME; ./configure >/dev/null 2>/dev/null)
|
||||
echo "Done."
|
||||
fi
|
||||
|
||||
echo "Ensuring node is built..."
|
||||
#make sure node is built
|
||||
$(cd $ABSOLUTE_NODE_HOME; make >/dev/null 2>/dev/null)
|
||||
echo "Done."
|
||||
|
||||
NODEJAR_HOME=$COMMON_ROOT/nodejar
|
||||
|
||||
if [ ! -e $NODEJAR_HOME ]; then
|
||||
echo "No node jar home found. cloning from depot..."
|
||||
$(cd $COMMON_ROOT; hg clone https://hg.kenai.com/hg/nodejs~source nodejar >/dev/null 2>/dev/null)
|
||||
$(cd $COMMON_ROOT/nodejar; ant >/dev/null)
|
||||
echo "Done."
|
||||
echo "Copying node files..."
|
||||
$(cd $COMMON_ROOT/nodejar; ant copy-node-files >/dev/null 2>/dev/null)
|
||||
echo "Patching node files..."
|
||||
$(cd $COMMON_ROOT/nodejar; ant patch-node-files >/dev/null 2>/dev/null)
|
||||
echo "Done."
|
||||
fi
|
||||
|
||||
echo "Ensuring node.jar is up to date from source depot..."
|
||||
$(cd $COMMON_ROOT/nodejar; hg pull -u >/dev/null 2>/dev/null)
|
||||
echo "Done."
|
||||
|
||||
echo "Installing nashorn..."
|
||||
$(cd $COMMON_ROOT/nodejar; ant >/dev/null)
|
||||
echo "Done."
|
||||
|
||||
echo "Running node.jar test..."
|
||||
$(cd $COMMON_ROOT/nodejar; mvn clean verify >$TESTNODEJAR_OUTPUT)
|
||||
echo "Done."
|
||||
|
||||
failure_check $TESTNODEJAR_OUTPUT
|
||||
|
||||
echo "**** SUCCESS: Node test successful."
|
||||
|
||||
if [ $KEEP_OUTPUT == "true" ]; then
|
||||
rm -fr $TESTNODEJAR_OUTPUT
|
||||
cp $TESTNODEJAR_OUTPUT ./checkintest.nodejar.log
|
||||
fi
|
||||
}
|
||||
|
||||
if [ $RUN_NODE != "false" ]; then
|
||||
testnode;
|
||||
fi;
|
||||
|
||||
echo "Finished"
|
||||
52
nashorn/bin/fixorphantests.sh
Normal file
52
nashorn/bin/fixorphantests.sh
Normal file
@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
#ensure that all tests tagged with @test are also tagged with @run
|
||||
|
||||
for f in $(find test/script/basic/*.js); do
|
||||
grep @test $f >/dev/null
|
||||
TEST=$?
|
||||
grep @run $f >/dev/null
|
||||
RUN=$?
|
||||
|
||||
if [ $TEST -eq 0 ] && [ ! $RUN -eq 0 ]; then
|
||||
echo "repairing ${f}..."
|
||||
TEMP=$(mktemp /tmp/scratch.XXXXXX)
|
||||
|
||||
#IFS='', -raw flag to preserve white space
|
||||
while IFS='' read -r line; do
|
||||
echo $line | grep @test >/dev/null
|
||||
TEST=$?
|
||||
printf "%s\n" "$line"
|
||||
if [ $TEST -eq 0 ]; then
|
||||
printf "%s\n" "$line" | sed s/@test/@run/g
|
||||
fi
|
||||
done < $f >$TEMP
|
||||
|
||||
cp $TEMP $f
|
||||
|
||||
rm -fr $TEMP
|
||||
fi
|
||||
|
||||
done
|
||||
30
nashorn/bin/fixwhitespace.sh
Normal file
30
nashorn/bin/fixwhitespace.sh
Normal file
@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
#convert tabs to spaces
|
||||
find . -name "*.java" -exec sed -i "" 's/ / /g' {} \;
|
||||
|
||||
#remove trailing whitespace
|
||||
find . -name "*.java" -exec sed -i "" 's/[ ]*$//' \{} \;
|
||||
|
||||
29
nashorn/bin/jjs
Normal file
29
nashorn/bin/jjs
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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. 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.
|
||||
#
|
||||
|
||||
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
|
||||
|
||||
$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
|
||||
27
nashorn/bin/jjs.bat
Normal file
27
nashorn/bin/jjs.bat
Normal file
@ -0,0 +1,27 @@
|
||||
rem
|
||||
rem Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
rem
|
||||
rem This code is free software; you can redistribute it and/or modify it
|
||||
rem under the terms of the GNU General Public License version 2 only, as
|
||||
rem published by the Free Software Foundation. Oracle designates this
|
||||
rem particular file as subject to the "Classpath" exception as provided
|
||||
rem by Oracle in the LICENSE file that accompanied this code.
|
||||
rem
|
||||
rem This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
rem version 2 for more details (a copy is included in the LICENSE file that
|
||||
rem accompanied this code).
|
||||
rem
|
||||
rem You should have received a copy of the GNU General Public License version
|
||||
rem 2 along with this work; if not, write to the Free Software Foundation,
|
||||
rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
rem
|
||||
rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
rem or visit www.oracle.com if you need additional information or have any
|
||||
rem questions.
|
||||
rem
|
||||
@echo off
|
||||
|
||||
java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.ext.dirs=%~dp0\..\dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false jdk.nashorn.tools.Shell
|
||||
29
nashorn/bin/jjssecure
Normal file
29
nashorn/bin/jjssecure
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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. 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.
|
||||
#
|
||||
|
||||
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
|
||||
|
||||
$JAVA_HOME/bin/java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=true -Dnashorn.home=`dirname $0`/.. -Djava.security.manager jdk.nashorn.tools.Shell $*
|
||||
27
nashorn/bin/jjssecure.bat
Normal file
27
nashorn/bin/jjssecure.bat
Normal file
@ -0,0 +1,27 @@
|
||||
rem
|
||||
rem Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
rem
|
||||
rem This code is free software; you can redistribute it and/or modify it
|
||||
rem under the terms of the GNU General Public License version 2 only, as
|
||||
rem published by the Free Software Foundation. Oracle designates this
|
||||
rem particular file as subject to the "Classpath" exception as provided
|
||||
rem by Oracle in the LICENSE file that accompanied this code.
|
||||
rem
|
||||
rem This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
rem version 2 for more details (a copy is included in the LICENSE file that
|
||||
rem accompanied this code).
|
||||
rem
|
||||
rem You should have received a copy of the GNU General Public License version
|
||||
rem 2 along with this work; if not, write to the Free Software Foundation,
|
||||
rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
rem
|
||||
rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
rem or visit www.oracle.com if you need additional information or have any
|
||||
rem questions.
|
||||
rem
|
||||
@echo off
|
||||
|
||||
java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.ext.dirs=%~dp0\..\dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.home=%~dp0\.. -Djava.security.manager jdk.nashorn.tools.Shell
|
||||
29
nashorn/bin/nashorn
Normal file
29
nashorn/bin/nashorn
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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. 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.
|
||||
#
|
||||
|
||||
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
|
||||
|
||||
$JAVA_HOME/bin/jrunscript -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $*
|
||||
27
nashorn/bin/nashorn.bat
Normal file
27
nashorn/bin/nashorn.bat
Normal file
@ -0,0 +1,27 @@
|
||||
rem
|
||||
rem Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
rem
|
||||
rem This code is free software; you can redistribute it and/or modify it
|
||||
rem under the terms of the GNU General Public License version 2 only, as
|
||||
rem published by the Free Software Foundation. Oracle designates this
|
||||
rem particular file as subject to the "Classpath" exception as provided
|
||||
rem by Oracle in the LICENSE file that accompanied this code.
|
||||
rem
|
||||
rem This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
rem version 2 for more details (a copy is included in the LICENSE file that
|
||||
rem accompanied this code).
|
||||
rem
|
||||
rem You should have received a copy of the GNU General Public License version
|
||||
rem 2 along with this work; if not, write to the Free Software Foundation,
|
||||
rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
rem
|
||||
rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
rem or visit www.oracle.com if you need additional information or have any
|
||||
rem questions.
|
||||
rem
|
||||
@echo off
|
||||
|
||||
jrunscript -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=%~dp0\..\dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Dnashorn.debug=true -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -l nashorn
|
||||
24
nashorn/bin/rm-non-tracked.sh
Normal file
24
nashorn/bin/rm-non-tracked.sh
Normal file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
hg status|grep ^\?|awk '{print $2}'|xargs rm
|
||||
59
nashorn/bin/verbose_octane.bat
Normal file
59
nashorn/bin/verbose_octane.bat
Normal file
@ -0,0 +1,59 @@
|
||||
rem
|
||||
rem Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
rem
|
||||
rem This code is free software; you can redistribute it and/or modify it
|
||||
rem under the terms of the GNU General Public License version 2 only, as
|
||||
rem published by the Free Software Foundation.
|
||||
rem
|
||||
rem This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
rem version 2 for more details (a copy is included in the LICENSE file that
|
||||
rem accompanied this code).
|
||||
rem
|
||||
rem You should have received a copy of the GNU General Public License version
|
||||
rem 2 along with this work; if not, write to the Free Software Foundation,
|
||||
rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
rem
|
||||
rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
rem or visit www.oracle.com if you need additional information or have any
|
||||
rem questions.
|
||||
rem
|
||||
@echo off
|
||||
|
||||
if "%JAVA_HOME%" neq "" (
|
||||
call :run "%JAVA_HOME%/bin/java"
|
||||
) else (
|
||||
call :run java
|
||||
)
|
||||
goto :EOF
|
||||
|
||||
:run
|
||||
setlocal
|
||||
set NASHORN_JAR=dist/nashorn.jar
|
||||
set JVM_FLAGS=-Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -jar %NASHORN_JAR%
|
||||
set JVM_FLAGS7=-Xbootclasspath/p:%NASHORN_JAR% %JVM_FLAGS%
|
||||
set OCTANE_ARGS=--verbose --iterations 7
|
||||
|
||||
%1 -fullversion 2>&1 | findstr /L /C:"version ""1.7"
|
||||
if %errorlevel% equ 0 (
|
||||
set CMD=%1 %JVM_FLAGS7%
|
||||
) else (
|
||||
%1 -fullversion
|
||||
set CMD=%1 %JVM_FLAGS%
|
||||
)
|
||||
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/box2d.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/code-load.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/crypto.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/deltablue.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/gbemu.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/navier-stokes.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/pdfjs.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/raytrace.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/regexp.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/richards.js %OCTANE_ARGS%
|
||||
%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/splay.js %OCTANE_ARGS%
|
||||
endlocal
|
||||
goto :EOF
|
||||
58
nashorn/bin/verbose_octane.sh
Normal file
58
nashorn/bin/verbose_octane.sh
Normal file
@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
# 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.
|
||||
#
|
||||
|
||||
ITERS=$1
|
||||
if [ -z $ITERS ]; then
|
||||
ITERS=7
|
||||
fi
|
||||
NASHORN_JAR=dist/nashorn.jar
|
||||
JVM_FLAGS="-XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:-TieredCompilation -server -jar ${NASHORN_JAR}"
|
||||
JVM_FLAGS7="-Xbootclasspath/p:${NASHORN_JAR} ${JVM_FLAGS}"
|
||||
OCTANE_ARGS="--verbose --iterations ${ITERS}"
|
||||
|
||||
BENCHMARKS=( "box2d.js" "code-load.js" "crypto.js" "deltablue.js" "earley-boyer.js" "gbemu.js" "navier-stokes.js" "raytrace.js" "regexp.js" "richards.js" "splay.js" )
|
||||
# TODO mandreel.js has metaspace issues
|
||||
|
||||
if [ ! -z $JAVA7_HOME ]; then
|
||||
echo "running ${ITERS} iterations with java7 using JAVA_HOME=${JAVA7_HOME}..."
|
||||
for BENCHMARK in "${BENCHMARKS[@]}"
|
||||
do
|
||||
CMD="${JAVA8_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/${BENCHMARK} ${OCTANE_ARGS}"
|
||||
$CMD
|
||||
done
|
||||
else
|
||||
echo "no JAVA7_HOME set. skipping java7"
|
||||
fi
|
||||
|
||||
if [ ! -z $JAVA8_HOME ]; then
|
||||
echo "running ${ITERS} iterations with java8 using JAVA_HOME=${JAVA8_HOME}..."
|
||||
for BENCHMARK in "${BENCHMARKS[@]}"
|
||||
do
|
||||
CMD="${JAVA8_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/${BENCHMARK} ${OCTANE_ARGS}"
|
||||
$CMD
|
||||
done
|
||||
else
|
||||
echo "no JAVA8_HOME set"
|
||||
fi
|
||||
|
||||
echo "Done"
|
||||
34
nashorn/buildtools/nasgen/README
Normal file
34
nashorn/buildtools/nasgen/README
Normal file
@ -0,0 +1,34 @@
|
||||
Nasgen is a tool for processing Java classes that implement native
|
||||
JavaScript objects. It does so by looking for the
|
||||
com.oracle.nashorn.objects.annotations.ScriptClass annotation and other
|
||||
annotations in that package.
|
||||
|
||||
For each class "C", nasgen instruments the original class and generates
|
||||
two additional classes: a "C$Prototype" class for the JavaScript
|
||||
prototype object, and a "C$Constructor" class for the JavaScript
|
||||
constructor function.
|
||||
|
||||
Each class instrumented or generated by nasgen contains a private static
|
||||
"$nasgenmap$" field of type com.oracle.nashorn.runtime.PropertyMap and
|
||||
static initializer block to initialize the field to the object's
|
||||
JavaScript properties.
|
||||
|
||||
Members annotated with @Function, @Property, @Getter, and @Setter are
|
||||
mapped to the $Constructor, $Prototype, or main class, depending on the
|
||||
value of the annotation's 'where' field. By default, @Property, @Getter,
|
||||
and @Setter belong to the main class while @Function methods without
|
||||
explicit 'where' field belong to the $Prototype class. The @Constructor
|
||||
annotation marks a method to be invoked as JavaScript constructor.
|
||||
|
||||
Nasgen enforces all @Function/@Getter/@Setter/@Constructor annotated
|
||||
methods to be declared as static. Static final @Property fields remain
|
||||
in the main class while other @Property fields are moved to respective
|
||||
classes depending on the annotation's 'where' value. For functions
|
||||
mapped to the $Prototype or $Constructor class, nasgen also generates
|
||||
getters and setters prefixed by G$ and S$, respectively.
|
||||
|
||||
Nasgen-generated classes are hidden from normal ClassLoaders by giving
|
||||
them a ".clazz" file name extension instead of the standard ".class"
|
||||
extension. This allows script classes to be loaded independently by each
|
||||
Nashorn context through the com.oracle.nashorn.runtime.StructureLoader
|
||||
class loader.
|
||||
60
nashorn/buildtools/nasgen/build.xml
Normal file
60
nashorn/buildtools/nasgen/build.xml
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project name="nasgen" default="all" basedir=".">
|
||||
<target name="init">
|
||||
<loadproperties srcFile="project.properties"/>
|
||||
</target>
|
||||
|
||||
<target name="prepare" depends="init">
|
||||
<mkdir dir="${build.classes.dir}"/>
|
||||
<mkdir dir="${dist.dir}"/>
|
||||
<mkdir dir="${dist.dir}/lib"/>
|
||||
</target>
|
||||
|
||||
<target name="clean" depends="init">
|
||||
<delete dir="${build.dir}"/>
|
||||
<delete dir="${dist.dir}"/>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="prepare" description="Compiles the nasgen sources">
|
||||
<javac srcdir="${src.dir}"
|
||||
destdir="${build.classes.dir}"
|
||||
classpath="${javac.classpath}"
|
||||
debug="${javac.debug}"
|
||||
includeantruntime="false">
|
||||
<compilerarg value="-Xlint:unchecked"/>
|
||||
<compilerarg value="-Xlint:deprecation"/>
|
||||
<compilerarg value="-XDignore.symbol.file"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile" description="Creates nasgen.jar">
|
||||
<jar jarfile="${dist.jar}" basedir="${build.classes.dir}" manifest="${meta.inf.dir}/MANIFEST.MF"/>
|
||||
</target>
|
||||
|
||||
<target name="dist" depends="jar"/>
|
||||
|
||||
<target name="all" depends="dist"
|
||||
description="Builds sources and generates nasgen.jar"/>
|
||||
</project>
|
||||
39
nashorn/buildtools/nasgen/nasgen.iml
Normal file
39
nashorn/buildtools/nasgen/nasgen.iml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/build/test/classes" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="asm" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
52
nashorn/buildtools/nasgen/project.properties
Normal file
52
nashorn/buildtools/nasgen/project.properties
Normal file
@ -0,0 +1,52 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
application.title=nasgen
|
||||
|
||||
# source and target levels
|
||||
build.compiler=modern
|
||||
javac.source=1.7
|
||||
javac.target=1.7
|
||||
|
||||
build.classes.dir=${build.dir}/classes
|
||||
|
||||
# This directory is removed when the project is cleaned:
|
||||
build.dir=build
|
||||
|
||||
# This directory is removed when the project is cleaned:
|
||||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/nasgen.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
|
||||
nashorn.dir=../../
|
||||
|
||||
javac.debug=true
|
||||
|
||||
javac.classpath=\
|
||||
${nashorn.dir}/build/classes
|
||||
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
run.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
run.jvmargs=
|
||||
src.dir=src
|
||||
4
nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF
Normal file
4
nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,4 @@
|
||||
Manifest-Version: 1.0
|
||||
Class-Path: lib/ant-1.7.1.jar
|
||||
Main-Class: jdk.nashorn.internal.tools.nasgen.Main
|
||||
|
||||
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.GETTER_PREFIX;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
|
||||
|
||||
/**
|
||||
* Base class for class generator classes.
|
||||
*
|
||||
*/
|
||||
public class ClassGenerator {
|
||||
/** ASM class writer used to output bytecode for this class */
|
||||
protected final ClassWriter cw;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
protected ClassGenerator() {
|
||||
this.cw = makeClassWriter();
|
||||
}
|
||||
|
||||
MethodGenerator makeStaticInitializer() {
|
||||
return makeStaticInitializer(cw);
|
||||
}
|
||||
|
||||
MethodGenerator makeConstructor() {
|
||||
return makeConstructor(cw);
|
||||
}
|
||||
|
||||
MethodGenerator makeMethod(final int access, final String name, final String desc) {
|
||||
return makeMethod(cw, access, name, desc);
|
||||
}
|
||||
|
||||
void addMapField() {
|
||||
addMapField(cw);
|
||||
}
|
||||
|
||||
void addField(final String name, final String desc) {
|
||||
addField(cw, name, desc);
|
||||
}
|
||||
|
||||
void addFunctionField(final String name) {
|
||||
addFunctionField(cw, name);
|
||||
}
|
||||
|
||||
void addGetter(final String owner, final MemberInfo memInfo) {
|
||||
addGetter(cw, owner, memInfo);
|
||||
}
|
||||
|
||||
void addSetter(final String owner, final MemberInfo memInfo) {
|
||||
addSetter(cw, owner, memInfo);
|
||||
}
|
||||
|
||||
void emitGetClassName(final String name) {
|
||||
final MethodGenerator mi = makeMethod(ACC_PUBLIC, GET_CLASS_NAME, GET_CLASS_NAME_DESC);
|
||||
mi.loadLiteral(name);
|
||||
mi.returnValue();
|
||||
mi.computeMaxs();
|
||||
mi.visitEnd();
|
||||
}
|
||||
|
||||
static ClassWriter makeClassWriter() {
|
||||
return new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
|
||||
@Override
|
||||
protected String getCommonSuperClass(final String type1, final String type2) {
|
||||
try {
|
||||
return super.getCommonSuperClass(type1, type2);
|
||||
} catch (final RuntimeException | LinkageError e) {
|
||||
return StringConstants.OBJECT_TYPE;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static MethodGenerator makeStaticInitializer(final ClassVisitor cv) {
|
||||
return makeStaticInitializer(cv, CLINIT);
|
||||
}
|
||||
|
||||
static MethodGenerator makeStaticInitializer(final ClassVisitor cv, final String name) {
|
||||
final int access = ACC_PUBLIC | ACC_STATIC;
|
||||
final String desc = DEFAULT_INIT_DESC;
|
||||
final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
|
||||
return new MethodGenerator(mv, access, name, desc);
|
||||
}
|
||||
|
||||
static MethodGenerator makeConstructor(final ClassVisitor cv) {
|
||||
final int access = ACC_PUBLIC;
|
||||
final String name = INIT;
|
||||
final String desc = DEFAULT_INIT_DESC;
|
||||
final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
|
||||
return new MethodGenerator(mv, access, name, desc);
|
||||
}
|
||||
|
||||
static MethodGenerator makeMethod(final ClassVisitor cv, final int access, final String name, final String desc) {
|
||||
final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
|
||||
return new MethodGenerator(mv, access, name, desc);
|
||||
}
|
||||
|
||||
static void emitStaticInitPrefix(final MethodGenerator mi, final String className) {
|
||||
mi.visitCode();
|
||||
mi.pushNull();
|
||||
mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC);
|
||||
mi.loadClass(className);
|
||||
mi.invokeStatic(MAP_TYPE, MAP_NEWMAP, MAP_NEWMAP_DESC);
|
||||
mi.storeLocal(0);
|
||||
}
|
||||
|
||||
static void emitStaticInitSuffix(final MethodGenerator mi, final String className) {
|
||||
mi.loadLocal(0);
|
||||
mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC);
|
||||
mi.returnVoid();
|
||||
mi.computeMaxs();
|
||||
mi.visitEnd();
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
private static Type memInfoType(final MemberInfo memInfo) {
|
||||
switch (memInfo.getJavaDesc().charAt(0)) {
|
||||
case 'I': return Type.INT_TYPE;
|
||||
case 'J': return Type.LONG_TYPE;
|
||||
case 'D': return Type.DOUBLE_TYPE;
|
||||
default: assert false : memInfo.getJavaDesc();
|
||||
case 'L': return TYPE_OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getterDesc(final MemberInfo memInfo) {
|
||||
return Type.getMethodDescriptor(memInfoType(memInfo));
|
||||
}
|
||||
|
||||
private static String setterDesc(final MemberInfo memInfo) {
|
||||
return Type.getMethodDescriptor(Type.VOID_TYPE, memInfoType(memInfo));
|
||||
}
|
||||
|
||||
static void addGetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) {
|
||||
final int access = ACC_PUBLIC;
|
||||
final String name = GETTER_PREFIX + memInfo.getJavaName();
|
||||
final String desc = getterDesc(memInfo);
|
||||
final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
|
||||
final MethodGenerator mi = new MethodGenerator(mv, access, name, desc);
|
||||
mi.visitCode();
|
||||
if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) {
|
||||
mi.getStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
} else {
|
||||
mi.loadLocal(0);
|
||||
mi.getField(owner, memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
}
|
||||
mi.returnValue();
|
||||
mi.computeMaxs();
|
||||
mi.visitEnd();
|
||||
}
|
||||
|
||||
static void addSetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) {
|
||||
final int access = ACC_PUBLIC;
|
||||
final String name = SETTER_PREFIX + memInfo.getJavaName();
|
||||
final String desc = setterDesc(memInfo);
|
||||
final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null);
|
||||
final MethodGenerator mi = new MethodGenerator(mv, access, name, desc);
|
||||
mi.visitCode();
|
||||
if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) {
|
||||
mi.loadLocal(1);
|
||||
mi.putStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
} else {
|
||||
mi.loadLocal(0);
|
||||
mi.loadLocal(1);
|
||||
mi.putField(owner, memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
}
|
||||
mi.returnVoid();
|
||||
mi.computeMaxs();
|
||||
mi.visitEnd();
|
||||
}
|
||||
|
||||
static void addMapField(final ClassVisitor cv) {
|
||||
// add a MAP static field
|
||||
final FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC,
|
||||
MAP_FIELD_NAME, MAP_DESC, null, null);
|
||||
if (fv != null) {
|
||||
fv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
static void addField(final ClassVisitor cv, final String name, final String desc) {
|
||||
final FieldVisitor fv = cv.visitField(ACC_PRIVATE, name, desc, null, null);
|
||||
if (fv != null) {
|
||||
fv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
static void addFunctionField(final ClassVisitor cv, final String name) {
|
||||
addField(cv, name, OBJECT_DESC);
|
||||
}
|
||||
|
||||
static void newFunction(final MethodGenerator mi, final String className, final MemberInfo memInfo, final List<MemberInfo> specs) {
|
||||
final boolean arityFound = (memInfo.getArity() != MemberInfo.DEFAULT_ARITY);
|
||||
|
||||
mi.loadLiteral(memInfo.getName());
|
||||
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, memInfo.getJavaName(), memInfo.getJavaDesc()));
|
||||
|
||||
assert specs != null;
|
||||
if (!specs.isEmpty()) {
|
||||
mi.memberInfoArray(className, specs);
|
||||
mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC);
|
||||
} else {
|
||||
mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC);
|
||||
}
|
||||
|
||||
if (arityFound) {
|
||||
mi.dup();
|
||||
mi.push(memInfo.getArity());
|
||||
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {
|
||||
final String propertyName = memInfo.getName();
|
||||
mi.loadLocal(0);
|
||||
mi.loadLiteral(propertyName);
|
||||
// setup flags
|
||||
mi.push(memInfo.getAttributes());
|
||||
// setup getter method handle
|
||||
String javaName = GETTER_PREFIX + memInfo.getJavaName();
|
||||
mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, getterDesc(memInfo)));
|
||||
// setup setter method handle
|
||||
if (memInfo.isFinal()) {
|
||||
mi.pushNull();
|
||||
} else {
|
||||
javaName = SETTER_PREFIX + memInfo.getJavaName();
|
||||
mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo)));
|
||||
}
|
||||
mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC);
|
||||
mi.storeLocal(0);
|
||||
}
|
||||
|
||||
static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo getter, final MemberInfo setter) {
|
||||
final String propertyName = getter.getName();
|
||||
mi.loadLocal(0);
|
||||
mi.loadLiteral(propertyName);
|
||||
// setup flags
|
||||
mi.push(getter.getAttributes());
|
||||
// setup getter method handle
|
||||
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className,
|
||||
getter.getJavaName(), getter.getJavaDesc()));
|
||||
// setup setter method handle
|
||||
if (setter == null) {
|
||||
mi.pushNull();
|
||||
} else {
|
||||
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className,
|
||||
setter.getJavaName(), setter.getJavaDesc()));
|
||||
}
|
||||
mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC);
|
||||
mi.storeLocal(0);
|
||||
}
|
||||
|
||||
static ScriptClassInfo getScriptClassInfo(final String fileName) throws IOException {
|
||||
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) {
|
||||
return getScriptClassInfo(new ClassReader(bis));
|
||||
}
|
||||
}
|
||||
|
||||
static ScriptClassInfo getScriptClassInfo(final byte[] classBuf) {
|
||||
return getScriptClassInfo(new ClassReader(classBuf));
|
||||
}
|
||||
|
||||
private static ScriptClassInfo getScriptClassInfo(final ClassReader reader) {
|
||||
final ScriptClassInfoCollector scic = new ScriptClassInfoCollector();
|
||||
reader.accept(scic, 0);
|
||||
return scic.getScriptClassInfo();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
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.H_INVOKESTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.CONSTRUCTOR_SUFFIX;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC3;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC4;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
|
||||
/**
|
||||
* This class generates constructor class for a @ClassInfo annotated class.
|
||||
*
|
||||
*/
|
||||
public class ConstructorGenerator extends ClassGenerator {
|
||||
private final ScriptClassInfo scriptClassInfo;
|
||||
private final String className;
|
||||
private final MemberInfo constructor;
|
||||
private final int memberCount;
|
||||
private final List<MemberInfo> specs;
|
||||
|
||||
ConstructorGenerator(final ScriptClassInfo sci) {
|
||||
this.scriptClassInfo = sci;
|
||||
|
||||
this.className = scriptClassInfo.getConstructorClassName();
|
||||
this.constructor = scriptClassInfo.getConstructor();
|
||||
this.memberCount = scriptClassInfo.getConstructorMemberCount();
|
||||
this.specs = scriptClassInfo.getSpecializedConstructors();
|
||||
}
|
||||
|
||||
byte[] getClassBytes() {
|
||||
// new class extensing from ScriptObject
|
||||
final String superClass = (constructor != null)? SCRIPTFUNCTIONIMPL_TYPE : SCRIPTOBJECT_TYPE;
|
||||
cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClass, null);
|
||||
if (memberCount > 0) {
|
||||
// add fields
|
||||
emitFields();
|
||||
// add <clinit>
|
||||
emitStaticInitializer();
|
||||
}
|
||||
// add <init>
|
||||
emitConstructor();
|
||||
|
||||
if (constructor == null) {
|
||||
emitGetClassName(scriptClassInfo.getName());
|
||||
}
|
||||
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
// --Internals only below this point
|
||||
private void emitFields() {
|
||||
// Introduce "Function" type instance fields for each
|
||||
// constructor @Function in script class and introduce instance
|
||||
// fields for each constructor @Property in the script class.
|
||||
for (MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (memInfo.isConstructorFunction()) {
|
||||
addFunctionField(memInfo.getJavaName());
|
||||
memInfo = (MemberInfo)memInfo.clone();
|
||||
memInfo.setJavaDesc(OBJECT_DESC);
|
||||
memInfo.setJavaAccess(ACC_PUBLIC);
|
||||
addGetter(className, memInfo);
|
||||
addSetter(className, memInfo);
|
||||
} else if (memInfo.isConstructorProperty()) {
|
||||
if (memInfo.isStaticFinal()) {
|
||||
addGetter(scriptClassInfo.getJavaName(), memInfo);
|
||||
} else {
|
||||
addField(memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
memInfo = (MemberInfo)memInfo.clone();
|
||||
memInfo.setJavaAccess(ACC_PUBLIC);
|
||||
addGetter(className, memInfo);
|
||||
addSetter(className, memInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addMapField();
|
||||
}
|
||||
|
||||
private void emitStaticInitializer() {
|
||||
final MethodGenerator mi = makeStaticInitializer();
|
||||
emitStaticInitPrefix(mi, className);
|
||||
|
||||
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (memInfo.isConstructorFunction() || memInfo.isConstructorProperty()) {
|
||||
linkerAddGetterSetter(mi, className, memInfo);
|
||||
} else if (memInfo.isConstructorGetter()) {
|
||||
final MemberInfo setter = scriptClassInfo.findSetter(memInfo);
|
||||
linkerAddGetterSetter(mi, className, memInfo, setter);
|
||||
}
|
||||
}
|
||||
emitStaticInitSuffix(mi, className);
|
||||
}
|
||||
|
||||
private void emitConstructor() {
|
||||
final MethodGenerator mi = makeConstructor();
|
||||
mi.visitCode();
|
||||
callSuper(mi);
|
||||
|
||||
if (memberCount > 0) {
|
||||
// initialize Function type fields
|
||||
initFunctionFields(mi);
|
||||
// initialize data fields
|
||||
initDataFields(mi);
|
||||
}
|
||||
|
||||
if (constructor != null) {
|
||||
final int arity = constructor.getArity();
|
||||
if (arity != MemberInfo.DEFAULT_ARITY) {
|
||||
mi.loadThis();
|
||||
mi.push(arity);
|
||||
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY,
|
||||
SCRIPTFUNCTION_SETARITY_DESC);
|
||||
}
|
||||
}
|
||||
mi.returnVoid();
|
||||
mi.computeMaxs();
|
||||
mi.visitEnd();
|
||||
}
|
||||
|
||||
private void loadMap(final MethodGenerator mi) {
|
||||
if (memberCount > 0) {
|
||||
mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC);
|
||||
// make sure we use duplicated PropertyMap so that original map
|
||||
// stays intact and so can be used for many globals in same context
|
||||
mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC);
|
||||
}
|
||||
}
|
||||
|
||||
private void callSuper(final MethodGenerator mi) {
|
||||
String superClass, superDesc;
|
||||
mi.loadThis();
|
||||
if (constructor == null) {
|
||||
// call ScriptObject.<init>
|
||||
superClass = SCRIPTOBJECT_TYPE;
|
||||
superDesc = (memberCount > 0) ? SCRIPTOBJECT_INIT_DESC : DEFAULT_INIT_DESC;
|
||||
loadMap(mi);
|
||||
} else {
|
||||
// call Function.<init>
|
||||
superClass = SCRIPTFUNCTIONIMPL_TYPE;
|
||||
superDesc = (memberCount > 0) ? SCRIPTFUNCTIONIMPL_INIT_DESC4 : SCRIPTFUNCTIONIMPL_INIT_DESC3;
|
||||
mi.loadLiteral(constructor.getName());
|
||||
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, scriptClassInfo.getJavaName(), constructor.getJavaName(), constructor.getJavaDesc()));
|
||||
loadMap(mi);
|
||||
mi.memberInfoArray(scriptClassInfo.getJavaName(), specs); //pushes null if specs empty
|
||||
}
|
||||
|
||||
mi.invokeSpecial(superClass, INIT, superDesc);
|
||||
}
|
||||
|
||||
private void initFunctionFields(final MethodGenerator mi) {
|
||||
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (!memInfo.isConstructorFunction()) {
|
||||
continue;
|
||||
}
|
||||
mi.loadThis();
|
||||
newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
|
||||
mi.putField(className, memInfo.getJavaName(), OBJECT_DESC);
|
||||
}
|
||||
}
|
||||
|
||||
private void initDataFields(final MethodGenerator mi) {
|
||||
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (!memInfo.isConstructorProperty() || memInfo.isFinal()) {
|
||||
continue;
|
||||
}
|
||||
final Object value = memInfo.getValue();
|
||||
if (value != null) {
|
||||
mi.loadThis();
|
||||
mi.loadLiteral(value);
|
||||
mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
} else if (!memInfo.getInitClass().isEmpty()) {
|
||||
final String clazz = memInfo.getInitClass();
|
||||
mi.loadThis();
|
||||
mi.newObject(clazz);
|
||||
mi.dup();
|
||||
mi.invokeSpecial(clazz, INIT, DEFAULT_INIT_DESC);
|
||||
mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
}
|
||||
}
|
||||
|
||||
if (constructor != null) {
|
||||
mi.loadThis();
|
||||
final String protoName = scriptClassInfo.getPrototypeClassName();
|
||||
mi.newObject(protoName);
|
||||
mi.dup();
|
||||
mi.invokeSpecial(protoName, INIT, DEFAULT_INIT_DESC);
|
||||
mi.dup();
|
||||
mi.loadThis();
|
||||
mi.invokeStatic(PROTOTYPEOBJECT_TYPE, PROTOTYPEOBJECT_SETCONSTRUCTOR,
|
||||
PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC);
|
||||
mi.putField(SCRIPTFUNCTION_TYPE, PROTOTYPE, OBJECT_DESC);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point for ConstructorGenerator run separately as an application. Will display
|
||||
* usage. Takes one argument, a class name.
|
||||
* @param args args vector
|
||||
* @throws IOException if class can't be read
|
||||
*/
|
||||
public static void main(final String[] args) throws IOException {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Usage: " + ConstructorGenerator.class.getName() + " <class>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
final String className = args[0].replace('.', '/');
|
||||
final ScriptClassInfo sci = getScriptClassInfo(className + ".class");
|
||||
if (sci == null) {
|
||||
System.err.println("No @ScriptClass in " + className);
|
||||
System.exit(2);
|
||||
throw new IOException(); // get rid of warning for sci.verify() below - may be null
|
||||
}
|
||||
|
||||
try {
|
||||
sci.verify();
|
||||
} catch (final Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
System.exit(3);
|
||||
}
|
||||
final ConstructorGenerator gen = new ConstructorGenerator(sci);
|
||||
try (FileOutputStream fos = new FileOutputStream(className + CONSTRUCTOR_SUFFIX + ".class")) {
|
||||
fos.write(gen.getClassBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
|
||||
|
||||
/**
|
||||
* Main class for the "nasgen" tool.
|
||||
*
|
||||
*/
|
||||
public class Main {
|
||||
private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug");
|
||||
|
||||
private interface ErrorReporter {
|
||||
public void error(String msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public entry point for Nasgen if invoked from command line. Nasgen takes three arguments
|
||||
* in order: input directory, package list, output directory
|
||||
*
|
||||
* @param args argument vector
|
||||
*/
|
||||
public static void main(final String[] args) {
|
||||
final ErrorReporter reporter = new ErrorReporter() {
|
||||
@Override
|
||||
public void error(final String msg) {
|
||||
Main.error(msg, 1);
|
||||
}
|
||||
};
|
||||
if (args.length == 3) {
|
||||
processAll(args[0], args[1], args[2], reporter);
|
||||
} else {
|
||||
error("Usage: nasgen <input-dir> <package-list> <output-dir>", 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processAll(final String in, final String pkgList, final String out, final ErrorReporter reporter) {
|
||||
final File inDir = new File(in);
|
||||
if (!inDir.exists() || !inDir.isDirectory()) {
|
||||
reporter.error(in + " does not exist or not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
final File outDir = new File(out);
|
||||
if (!outDir.exists() || !outDir.isDirectory()) {
|
||||
reporter.error(out + " does not exist or not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
final String[] packages = pkgList.split(":");
|
||||
for (String pkg : packages) {
|
||||
pkg = pkg.replace('.', File.separatorChar);
|
||||
final File dir = new File(inDir, pkg);
|
||||
final File[] classes = dir.listFiles();
|
||||
for (final File clazz : classes) {
|
||||
if (clazz.isFile() && clazz.getName().endsWith(".class")) {
|
||||
if (! process(clazz, new File(outDir, pkg), reporter)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean process(final File inFile, final File outDir, final ErrorReporter reporter) {
|
||||
try {
|
||||
byte[] buf = new byte[(int)inFile.length()];
|
||||
|
||||
try (FileInputStream fin = new FileInputStream(inFile)) {
|
||||
fin.read(buf);
|
||||
}
|
||||
|
||||
final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(buf);
|
||||
|
||||
if (sci != null) {
|
||||
try {
|
||||
sci.verify();
|
||||
} catch (final Exception e) {
|
||||
reporter.error(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
// create necessary output package dir
|
||||
outDir.mkdirs();
|
||||
|
||||
// instrument @ScriptClass
|
||||
final ClassWriter writer = ClassGenerator.makeClassWriter();
|
||||
final ClassReader reader = new ClassReader(buf);
|
||||
final ScriptClassInstrumentor inst = new ScriptClassInstrumentor(writer, sci);
|
||||
reader.accept(inst, 0);
|
||||
//noinspection UnusedAssignment
|
||||
|
||||
// write instrumented class
|
||||
try (FileOutputStream fos = new FileOutputStream(new File(outDir, inFile.getName()))) {
|
||||
buf = writer.toByteArray();
|
||||
if (DEBUG) {
|
||||
verify(buf);
|
||||
}
|
||||
fos.write(buf);
|
||||
}
|
||||
|
||||
// simple class name without package prefix
|
||||
String simpleName = inFile.getName();
|
||||
simpleName = simpleName.substring(0, simpleName.indexOf(".class"));
|
||||
|
||||
if (sci.getPrototypeMemberCount() > 0) {
|
||||
// generate prototype class
|
||||
final PrototypeGenerator protGen = new PrototypeGenerator(sci);
|
||||
buf = protGen.getClassBytes();
|
||||
if (DEBUG) {
|
||||
verify(buf);
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.PROTOTYPE_SUFFIX + ".class"))) {
|
||||
fos.write(buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (sci.getConstructorMemberCount() > 0 || sci.getConstructor() != null) {
|
||||
// generate constructor class
|
||||
final ConstructorGenerator consGen = new ConstructorGenerator(sci);
|
||||
buf = consGen.getClassBytes();
|
||||
if (DEBUG) {
|
||||
verify(buf);
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.CONSTRUCTOR_SUFFIX + ".class"))) {
|
||||
fos.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (final IOException | RuntimeException e) {
|
||||
if (DEBUG) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
reporter.error(e.getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void verify(final byte[] buf) {
|
||||
final ClassReader cr = new ClassReader(buf);
|
||||
CheckClassAdapter.verify(cr, false, new PrintWriter(System.err));
|
||||
}
|
||||
|
||||
private static void error(final String msg, final int exitCode) {
|
||||
System.err.println(msg);
|
||||
System.exit(exitCode);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.nashorn.internal.objects.annotations.Where;
|
||||
|
||||
/**
|
||||
* Details about a Java method or field annotated with any of the field/method
|
||||
* annotations from the jdk.nashorn.internal.objects.annotations package.
|
||||
*/
|
||||
public final class MemberInfo implements Cloneable {
|
||||
/**
|
||||
* The different kinds of available class annotations
|
||||
*/
|
||||
public static enum Kind {
|
||||
/** This is a script class */
|
||||
SCRIPT_CLASS,
|
||||
/** This is a constructor */
|
||||
CONSTRUCTOR,
|
||||
/** This is a function */
|
||||
FUNCTION,
|
||||
/** This is a getter */
|
||||
GETTER,
|
||||
/** This is a setter */
|
||||
SETTER,
|
||||
/** This is a property */
|
||||
PROPERTY,
|
||||
/** This is a specialized version of a function */
|
||||
SPECIALIZED_FUNCTION,
|
||||
/** This is a specialized version of a constructor */
|
||||
SPECIALIZED_CONSTRUCTOR
|
||||
}
|
||||
|
||||
// keep in sync with jdk.nashorn.internal.objects.annotations.Attribute
|
||||
static final int DEFAULT_ATTRIBUTES = 0x0;
|
||||
|
||||
static final int DEFAULT_ARITY = -2;
|
||||
|
||||
// the kind of the script annotation - one of the above constants
|
||||
private MemberInfo.Kind kind;
|
||||
// script property name
|
||||
private String name;
|
||||
// script property attributes
|
||||
private int attributes;
|
||||
// name of the java member
|
||||
private String javaName;
|
||||
// type descriptor of the java member
|
||||
private String javaDesc;
|
||||
// access bits of the Java field or method
|
||||
private int javaAccess;
|
||||
// initial value for static @Property fields
|
||||
private Object value;
|
||||
// class whose object is created to fill property value
|
||||
private String initClass;
|
||||
// arity of the Function or Constructor
|
||||
private int arity;
|
||||
|
||||
private Where where;
|
||||
|
||||
/**
|
||||
* @return the kind
|
||||
*/
|
||||
public Kind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kind the kind to set
|
||||
*/
|
||||
public void setKind(final Kind kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the attributes
|
||||
*/
|
||||
public int getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attributes the attributes to set
|
||||
*/
|
||||
public void setAttributes(final int attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the javaName
|
||||
*/
|
||||
public String getJavaName() {
|
||||
return javaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param javaName the javaName to set
|
||||
*/
|
||||
public void setJavaName(final String javaName) {
|
||||
this.javaName = javaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the javaDesc
|
||||
*/
|
||||
public String getJavaDesc() {
|
||||
return javaDesc;
|
||||
}
|
||||
|
||||
void setJavaDesc(final String javaDesc) {
|
||||
this.javaDesc = javaDesc;
|
||||
}
|
||||
|
||||
int getJavaAccess() {
|
||||
return javaAccess;
|
||||
}
|
||||
|
||||
void setJavaAccess(final int access) {
|
||||
this.javaAccess = access;
|
||||
}
|
||||
|
||||
Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
void setValue(final Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
Where getWhere() {
|
||||
return where;
|
||||
}
|
||||
|
||||
void setWhere(final Where where) {
|
||||
this.where = where;
|
||||
}
|
||||
|
||||
boolean isFinal() {
|
||||
return (javaAccess & Opcodes.ACC_FINAL) != 0;
|
||||
}
|
||||
|
||||
boolean isStatic() {
|
||||
return (javaAccess & Opcodes.ACC_STATIC) != 0;
|
||||
}
|
||||
|
||||
boolean isStaticFinal() {
|
||||
return isStatic() && isFinal();
|
||||
}
|
||||
|
||||
boolean isInstanceGetter() {
|
||||
return kind == Kind.GETTER && where == Where.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this MemberInfo is a getter that resides in the instance
|
||||
* @return true if instance setter
|
||||
*/
|
||||
boolean isInstanceSetter() {
|
||||
return kind == Kind.SETTER && where == Where.INSTANCE;
|
||||
}
|
||||
|
||||
boolean isInstanceProperty() {
|
||||
return kind == Kind.PROPERTY && where == Where.INSTANCE;
|
||||
}
|
||||
|
||||
boolean isInstanceFunction() {
|
||||
return kind == Kind.FUNCTION && where == Where.INSTANCE;
|
||||
}
|
||||
|
||||
boolean isPrototypeGetter() {
|
||||
return kind == Kind.GETTER && where == Where.PROTOTYPE;
|
||||
}
|
||||
|
||||
boolean isPrototypeSetter() {
|
||||
return kind == Kind.SETTER && where == Where.PROTOTYPE;
|
||||
}
|
||||
|
||||
boolean isPrototypeProperty() {
|
||||
return kind == Kind.PROPERTY && where == Where.PROTOTYPE;
|
||||
}
|
||||
|
||||
boolean isPrototypeFunction() {
|
||||
return kind == Kind.FUNCTION && where == Where.PROTOTYPE;
|
||||
}
|
||||
|
||||
boolean isConstructorGetter() {
|
||||
return kind == Kind.GETTER && where == Where.CONSTRUCTOR;
|
||||
}
|
||||
|
||||
boolean isConstructorSetter() {
|
||||
return kind == Kind.SETTER && where == Where.CONSTRUCTOR;
|
||||
}
|
||||
|
||||
boolean isConstructorProperty() {
|
||||
return kind == Kind.PROPERTY && where == Where.CONSTRUCTOR;
|
||||
}
|
||||
|
||||
boolean isConstructorFunction() {
|
||||
return kind == Kind.FUNCTION && where == Where.CONSTRUCTOR;
|
||||
}
|
||||
|
||||
boolean isConstructor() {
|
||||
return kind == Kind.CONSTRUCTOR;
|
||||
}
|
||||
|
||||
void verify() {
|
||||
if (kind == Kind.CONSTRUCTOR) {
|
||||
final Type returnType = Type.getReturnType(javaDesc);
|
||||
if (! returnType.toString().equals(OBJECT_DESC)) {
|
||||
error("return value should be of Object type, found" + returnType);
|
||||
}
|
||||
final Type[] argTypes = Type.getArgumentTypes(javaDesc);
|
||||
if (argTypes.length < 2) {
|
||||
error("constructor methods should have at least 2 args");
|
||||
}
|
||||
if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) {
|
||||
error("first argument should be of boolean type, found" + argTypes[0]);
|
||||
}
|
||||
if (! argTypes[1].toString().equals(OBJECT_DESC)) {
|
||||
error("second argument should be of Object type, found" + argTypes[0]);
|
||||
}
|
||||
|
||||
if (argTypes.length > 2) {
|
||||
for (int i = 2; i < argTypes.length - 1; i++) {
|
||||
if (! argTypes[i].toString().equals(OBJECT_DESC)) {
|
||||
error(i + "'th argument should be of Object type, found " + argTypes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
final String lastArgType = argTypes[argTypes.length - 1].toString();
|
||||
final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC);
|
||||
if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) {
|
||||
error("last argument is neither Object nor Object[] type: " + lastArgType);
|
||||
}
|
||||
|
||||
if (isVarArg && argTypes.length > 3) {
|
||||
error("vararg constructor has more than 3 arguments");
|
||||
}
|
||||
}
|
||||
} else if (kind == Kind.FUNCTION) {
|
||||
final Type returnType = Type.getReturnType(javaDesc);
|
||||
if (! returnType.toString().equals(OBJECT_DESC)) {
|
||||
error("return value should be of Object type, found" + returnType);
|
||||
}
|
||||
final Type[] argTypes = Type.getArgumentTypes(javaDesc);
|
||||
if (argTypes.length < 1) {
|
||||
error("function methods should have at least 1 arg");
|
||||
}
|
||||
if (! argTypes[0].toString().equals(OBJECT_DESC)) {
|
||||
error("first argument should be of Object type, found" + argTypes[0]);
|
||||
}
|
||||
|
||||
if (argTypes.length > 1) {
|
||||
for (int i = 1; i < argTypes.length - 1; i++) {
|
||||
if (! argTypes[i].toString().equals(OBJECT_DESC)) {
|
||||
error(i + "'th argument should be of Object type, found " + argTypes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
final String lastArgType = argTypes[argTypes.length - 1].toString();
|
||||
final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC);
|
||||
if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) {
|
||||
error("last argument is neither Object nor Object[] type: " + lastArgType);
|
||||
}
|
||||
|
||||
if (isVarArg && argTypes.length > 2) {
|
||||
error("vararg function has more than 2 arguments");
|
||||
}
|
||||
}
|
||||
} else if (kind == Kind.GETTER) {
|
||||
final Type[] argTypes = Type.getArgumentTypes(javaDesc);
|
||||
if (argTypes.length != 1) {
|
||||
error("getter methods should have one argument");
|
||||
}
|
||||
if (! argTypes[0].toString().equals(OBJECT_DESC)) {
|
||||
error("first argument of getter should be of Object type, found: " + argTypes[0]);
|
||||
}
|
||||
if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) {
|
||||
error("return type of getter should not be void");
|
||||
}
|
||||
} else if (kind == Kind.SETTER) {
|
||||
final Type[] argTypes = Type.getArgumentTypes(javaDesc);
|
||||
if (argTypes.length != 2) {
|
||||
error("setter methods should have two arguments");
|
||||
}
|
||||
if (! argTypes[0].toString().equals(OBJECT_DESC)) {
|
||||
error("first argument of setter should be of Object type, found: " + argTypes[0]);
|
||||
}
|
||||
if (!Type.getReturnType(javaDesc).toString().equals("V")) {
|
||||
error("return type of setter should be void, found: " + Type.getReturnType(javaDesc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void error(final String msg) {
|
||||
throw new RuntimeException(javaName + javaDesc + " : " + msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the initClass
|
||||
*/
|
||||
String getInitClass() {
|
||||
return initClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param initClass the initClass to set
|
||||
*/
|
||||
void setInitClass(final String initClass) {
|
||||
this.initClass = initClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (final CloneNotSupportedException e) {
|
||||
assert false : "clone not supported " + e;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the arity
|
||||
*/
|
||||
int getArity() {
|
||||
return arity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param arity the arity to set
|
||||
*/
|
||||
void setArity(final int arity) {
|
||||
this.arity = arity;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,426 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.AASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ASM4;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.BALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.BASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.CALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.CASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.FALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.FASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
|
||||
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.INVOKEVIRTUAL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.POP;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE;
|
||||
|
||||
import java.util.List;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* Base class for all method generating classes.
|
||||
*
|
||||
*/
|
||||
public class MethodGenerator extends MethodVisitor {
|
||||
private final int access;
|
||||
private final String name;
|
||||
private final String descriptor;
|
||||
private final Type returnType;
|
||||
private final Type[] argumentTypes;
|
||||
|
||||
MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) {
|
||||
super(ASM4, mv);
|
||||
this.access = access;
|
||||
this.name = name;
|
||||
this.descriptor = descriptor;
|
||||
this.returnType = Type.getReturnType(descriptor);
|
||||
this.argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
}
|
||||
|
||||
int getAccess() {
|
||||
return access;
|
||||
}
|
||||
|
||||
final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
final String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
final Type getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
final Type[] getArgumentTypes() {
|
||||
return argumentTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether access for this method is static
|
||||
* @return true if static
|
||||
*/
|
||||
protected final boolean isStatic() {
|
||||
return (getAccess() & ACC_STATIC) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this method is a constructor
|
||||
* @return true if constructor
|
||||
*/
|
||||
protected final boolean isConstructor() {
|
||||
return "<init>".equals(name);
|
||||
}
|
||||
|
||||
void newObject(final String type) {
|
||||
super.visitTypeInsn(NEW, type);
|
||||
}
|
||||
|
||||
void newObjectArray(final String type) {
|
||||
super.visitTypeInsn(ANEWARRAY, type);
|
||||
}
|
||||
|
||||
void loadThis() {
|
||||
if ((access & ACC_STATIC) != 0) {
|
||||
throw new IllegalStateException("no 'this' inside static method");
|
||||
}
|
||||
super.visitVarInsn(ALOAD, 0);
|
||||
}
|
||||
|
||||
void returnValue() {
|
||||
super.visitInsn(returnType.getOpcode(IRETURN));
|
||||
}
|
||||
|
||||
void returnVoid() {
|
||||
super.visitInsn(RETURN);
|
||||
}
|
||||
|
||||
// load, store
|
||||
void arrayLoad(final Type type) {
|
||||
super.visitInsn(type.getOpcode(IALOAD));
|
||||
}
|
||||
|
||||
void arrayLoad() {
|
||||
super.visitInsn(AALOAD);
|
||||
}
|
||||
|
||||
void arrayStore(final Type type) {
|
||||
super.visitInsn(type.getOpcode(IASTORE));
|
||||
}
|
||||
|
||||
void arrayStore() {
|
||||
super.visitInsn(AASTORE);
|
||||
}
|
||||
|
||||
void loadLiteral(final Object value) {
|
||||
super.visitLdcInsn(value);
|
||||
}
|
||||
|
||||
void classLiteral(final String className) {
|
||||
super.visitLdcInsn(className);
|
||||
}
|
||||
|
||||
void loadLocal(final Type type, final int index) {
|
||||
super.visitVarInsn(type.getOpcode(ILOAD), index);
|
||||
}
|
||||
|
||||
void loadLocal(final int index) {
|
||||
super.visitVarInsn(ALOAD, index);
|
||||
}
|
||||
|
||||
void storeLocal(final Type type, final int index) {
|
||||
super.visitVarInsn(type.getOpcode(ISTORE), index);
|
||||
}
|
||||
|
||||
void storeLocal(final int index) {
|
||||
super.visitVarInsn(ASTORE, index);
|
||||
}
|
||||
|
||||
void checkcast(final String type) {
|
||||
super.visitTypeInsn(CHECKCAST, type);
|
||||
}
|
||||
|
||||
// push constants/literals
|
||||
void pushNull() {
|
||||
super.visitInsn(ACONST_NULL);
|
||||
}
|
||||
|
||||
void push(final int value) {
|
||||
if (value >= -1 && value <= 5) {
|
||||
super.visitInsn(ICONST_0 + value);
|
||||
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
||||
super.visitIntInsn(BIPUSH, value);
|
||||
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||
super.visitIntInsn(SIPUSH, value);
|
||||
} else {
|
||||
super.visitLdcInsn(value);
|
||||
}
|
||||
}
|
||||
|
||||
void loadClass(final String className) {
|
||||
super.visitLdcInsn(Type.getObjectType(className));
|
||||
}
|
||||
|
||||
void pop() {
|
||||
super.visitInsn(POP);
|
||||
}
|
||||
|
||||
// various "dups"
|
||||
void dup() {
|
||||
super.visitInsn(DUP);
|
||||
}
|
||||
|
||||
void dup2() {
|
||||
super.visitInsn(DUP2);
|
||||
}
|
||||
|
||||
void swap() {
|
||||
super.visitInsn(SWAP);
|
||||
}
|
||||
|
||||
void dupArrayValue(final int arrayOpcode) {
|
||||
switch (arrayOpcode) {
|
||||
case IALOAD: case FALOAD:
|
||||
case AALOAD: case BALOAD:
|
||||
case CALOAD: case SALOAD:
|
||||
case IASTORE: case FASTORE:
|
||||
case AASTORE: case BASTORE:
|
||||
case CASTORE: case SASTORE:
|
||||
dup();
|
||||
break;
|
||||
|
||||
case LALOAD: case DALOAD:
|
||||
case LASTORE: case DASTORE:
|
||||
dup2();
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("invalid dup");
|
||||
}
|
||||
}
|
||||
|
||||
void dupReturnValue(final int returnOpcode) {
|
||||
switch (returnOpcode) {
|
||||
case IRETURN:
|
||||
case FRETURN:
|
||||
case ARETURN:
|
||||
super.visitInsn(DUP);
|
||||
return;
|
||||
case LRETURN:
|
||||
case DRETURN:
|
||||
super.visitInsn(DUP2);
|
||||
return;
|
||||
case RETURN:
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException("not return");
|
||||
}
|
||||
}
|
||||
|
||||
void dupValue(final Type type) {
|
||||
switch (type.getSize()) {
|
||||
case 1:
|
||||
dup();
|
||||
break;
|
||||
case 2:
|
||||
dup2();
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("invalid dup");
|
||||
}
|
||||
}
|
||||
|
||||
void dupValue(final String desc) {
|
||||
final int typeCode = desc.charAt(0);
|
||||
switch (typeCode) {
|
||||
case '[':
|
||||
case 'L':
|
||||
case 'Z':
|
||||
case 'C':
|
||||
case 'B':
|
||||
case 'S':
|
||||
case 'I':
|
||||
super.visitInsn(DUP);
|
||||
break;
|
||||
case 'J':
|
||||
case 'D':
|
||||
super.visitInsn(DUP2);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("invalid signature");
|
||||
}
|
||||
}
|
||||
|
||||
// push default value of given type desc
|
||||
void defaultValue(final String desc) {
|
||||
final int typeCode = desc.charAt(0);
|
||||
switch (typeCode) {
|
||||
case '[':
|
||||
case 'L':
|
||||
super.visitInsn(ACONST_NULL);
|
||||
break;
|
||||
case 'Z':
|
||||
case 'C':
|
||||
case 'B':
|
||||
case 'S':
|
||||
case 'I':
|
||||
super.visitInsn(ICONST_0);
|
||||
break;
|
||||
case 'J':
|
||||
super.visitInsn(LCONST_0);
|
||||
break;
|
||||
case 'F':
|
||||
super.visitInsn(FCONST_0);
|
||||
break;
|
||||
case 'D':
|
||||
super.visitInsn(DCONST_0);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("invalid desc " + desc);
|
||||
}
|
||||
}
|
||||
|
||||
// invokes, field get/sets
|
||||
void invokeVirtual(final String owner, final String method, final String desc) {
|
||||
super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc);
|
||||
}
|
||||
|
||||
void invokeSpecial(final String owner, final String method, final String desc) {
|
||||
super.visitMethodInsn(INVOKESPECIAL, owner, method, desc);
|
||||
}
|
||||
|
||||
void invokeStatic(final String owner, final String method, final String desc) {
|
||||
super.visitMethodInsn(INVOKESTATIC, owner, method, desc);
|
||||
}
|
||||
|
||||
void putStatic(final String owner, final String field, final String desc) {
|
||||
super.visitFieldInsn(PUTSTATIC, owner, field, desc);
|
||||
}
|
||||
|
||||
void getStatic(final String owner, final String field, final String desc) {
|
||||
super.visitFieldInsn(GETSTATIC, owner, field, desc);
|
||||
}
|
||||
|
||||
void putField(final String owner, final String field, final String desc) {
|
||||
super.visitFieldInsn(PUTFIELD, owner, field, desc);
|
||||
}
|
||||
|
||||
void getField(final String owner, final String field, final String desc) {
|
||||
super.visitFieldInsn(GETFIELD, owner, field, desc);
|
||||
}
|
||||
|
||||
void memberInfoArray(final String className, final List<MemberInfo> mis) {
|
||||
if (mis.isEmpty()) {
|
||||
pushNull();
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
push(mis.size());
|
||||
newObjectArray(METHODHANDLE_TYPE);
|
||||
for (final MemberInfo mi : mis) {
|
||||
dup();
|
||||
push(pos++);
|
||||
visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc()));
|
||||
arrayStore(TYPE_METHODHANDLE);
|
||||
}
|
||||
}
|
||||
|
||||
void computeMaxs() {
|
||||
// These values are ignored as we create class writer
|
||||
// with ClassWriter.COMPUTE_MAXS flag.
|
||||
super.visitMaxs(Short.MAX_VALUE, Short.MAX_VALUE);
|
||||
}
|
||||
|
||||
// debugging support - print calls
|
||||
void println(final String msg) {
|
||||
super.visitFieldInsn(GETSTATIC,
|
||||
"java/lang/System",
|
||||
"out",
|
||||
"Ljava/io/PrintStream;");
|
||||
super.visitLdcInsn(msg);
|
||||
super.visitMethodInsn(INVOKEVIRTUAL,
|
||||
"java/io/PrintStream",
|
||||
"println",
|
||||
"(Ljava/lang/String;)V");
|
||||
}
|
||||
|
||||
// print the object on the top of the stack
|
||||
void printObject() {
|
||||
super.visitFieldInsn(GETSTATIC,
|
||||
"java/lang/System",
|
||||
"out",
|
||||
"Ljava/io/PrintStream;");
|
||||
super.visitInsn(SWAP);
|
||||
super.visitMethodInsn(INVOKEVIRTUAL,
|
||||
"java/io/PrintStream",
|
||||
"println",
|
||||
"(Ljava/lang/Object;)V");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A visitor that does nothing on visitXXX calls.
|
||||
*
|
||||
*/
|
||||
public class NullVisitor extends ClassVisitor {
|
||||
NullVisitor() {
|
||||
super(Opcodes.ASM4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(
|
||||
final int access,
|
||||
final String name,
|
||||
final String desc,
|
||||
final String signature,
|
||||
final String[] exceptions) {
|
||||
return new MethodVisitor(Opcodes.ASM4) {
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
return new NullAnnotationVisitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
return new NullAnnotationVisitor();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(
|
||||
final int access,
|
||||
final String name,
|
||||
final String desc,
|
||||
final String signature,
|
||||
final Object value) {
|
||||
return new FieldVisitor(Opcodes.ASM4) {
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
return new NullAnnotationVisitor();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
|
||||
return new NullAnnotationVisitor();
|
||||
}
|
||||
|
||||
private static class NullAnnotationVisitor extends AnnotationVisitor {
|
||||
NullAnnotationVisitor() {
|
||||
super(Opcodes.ASM4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
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.V1_7;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE_SUFFIX;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class generates prototype class for a @ClassInfo annotated class.
|
||||
*
|
||||
*/
|
||||
public class PrototypeGenerator extends ClassGenerator {
|
||||
private final ScriptClassInfo scriptClassInfo;
|
||||
private final String className;
|
||||
private final int memberCount;
|
||||
|
||||
PrototypeGenerator(final ScriptClassInfo sci) {
|
||||
this.scriptClassInfo = sci;
|
||||
this.className = scriptClassInfo.getPrototypeClassName();
|
||||
this.memberCount = scriptClassInfo.getPrototypeMemberCount();
|
||||
}
|
||||
|
||||
byte[] getClassBytes() {
|
||||
// new class extensing from ScriptObject
|
||||
cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, PROTOTYPEOBJECT_TYPE, null);
|
||||
if (memberCount > 0) {
|
||||
// add fields
|
||||
emitFields();
|
||||
// add <clinit>
|
||||
emitStaticInitializer();
|
||||
}
|
||||
// add <init>
|
||||
emitConstructor();
|
||||
|
||||
// add getClassName()
|
||||
emitGetClassName(scriptClassInfo.getName());
|
||||
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
// --Internals only below this point
|
||||
private void emitFields() {
|
||||
// introduce "Function" type instance fields for each
|
||||
// prototype @Function in script class info
|
||||
for (MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (memInfo.isPrototypeFunction()) {
|
||||
addFunctionField(memInfo.getJavaName());
|
||||
memInfo = (MemberInfo)memInfo.clone();
|
||||
memInfo.setJavaDesc(OBJECT_DESC);
|
||||
addGetter(className, memInfo);
|
||||
addSetter(className, memInfo);
|
||||
} else if (memInfo.isPrototypeProperty()) {
|
||||
if (memInfo.isStaticFinal()) {
|
||||
addGetter(scriptClassInfo.getJavaName(), memInfo);
|
||||
} else {
|
||||
addField(memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
memInfo = (MemberInfo)memInfo.clone();
|
||||
memInfo.setJavaAccess(ACC_PUBLIC);
|
||||
addGetter(className, memInfo);
|
||||
addSetter(className, memInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addMapField();
|
||||
}
|
||||
|
||||
private void emitStaticInitializer() {
|
||||
final MethodGenerator mi = makeStaticInitializer();
|
||||
emitStaticInitPrefix(mi, className);
|
||||
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (memInfo.isPrototypeFunction() || memInfo.isPrototypeProperty()) {
|
||||
linkerAddGetterSetter(mi, className, memInfo);
|
||||
} else if (memInfo.isPrototypeGetter()) {
|
||||
final MemberInfo setter = scriptClassInfo.findSetter(memInfo);
|
||||
linkerAddGetterSetter(mi, className, memInfo, setter);
|
||||
}
|
||||
}
|
||||
emitStaticInitSuffix(mi, className);
|
||||
}
|
||||
|
||||
private void emitConstructor() {
|
||||
final MethodGenerator mi = makeConstructor();
|
||||
mi.visitCode();
|
||||
mi.loadThis();
|
||||
if (memberCount > 0) {
|
||||
// call "super(map$)"
|
||||
mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC);
|
||||
// make sure we use duplicated PropertyMap so that original map
|
||||
// stays intact and so can be used for many globals in same context
|
||||
mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC);
|
||||
mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC);
|
||||
// initialize Function type fields
|
||||
initFunctionFields(mi);
|
||||
} else {
|
||||
// call "super()"
|
||||
mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, DEFAULT_INIT_DESC);
|
||||
}
|
||||
mi.returnVoid();
|
||||
mi.computeMaxs();
|
||||
mi.visitEnd();
|
||||
}
|
||||
|
||||
private void initFunctionFields(final MethodGenerator mi) {
|
||||
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (! memInfo.isPrototypeFunction()) {
|
||||
continue;
|
||||
}
|
||||
mi.loadThis();
|
||||
newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
|
||||
mi.putField(className, memInfo.getJavaName(), OBJECT_DESC);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* External entry point for PrototypeGenerator if called from the command line
|
||||
*
|
||||
* @param args arguments, takes 1 argument which is the class to process
|
||||
* @throws IOException if class cannot be read
|
||||
*/
|
||||
public static void main(final String[] args) throws IOException {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Usage: " + ConstructorGenerator.class.getName() + " <class>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
final String className = args[0].replace('.', '/');
|
||||
final ScriptClassInfo sci = getScriptClassInfo(className + ".class");
|
||||
if (sci == null) {
|
||||
System.err.println("No @ScriptClass in " + className);
|
||||
System.exit(2);
|
||||
throw new AssertionError(); //guard against warning that sci is null below
|
||||
}
|
||||
try {
|
||||
sci.verify();
|
||||
} catch (final Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
System.exit(3);
|
||||
}
|
||||
final PrototypeGenerator gen = new PrototypeGenerator(sci);
|
||||
try (FileOutputStream fos = new FileOutputStream(className + PROTOTYPE_SUFFIX + ".class")) {
|
||||
fos.write(gen.getClassBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.nashorn.internal.objects.annotations.Constructor;
|
||||
import jdk.nashorn.internal.objects.annotations.Function;
|
||||
import jdk.nashorn.internal.objects.annotations.Getter;
|
||||
import jdk.nashorn.internal.objects.annotations.Property;
|
||||
import jdk.nashorn.internal.objects.annotations.ScriptClass;
|
||||
import jdk.nashorn.internal.objects.annotations.Setter;
|
||||
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
|
||||
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
|
||||
import jdk.nashorn.internal.objects.annotations.Where;
|
||||
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
|
||||
|
||||
/**
|
||||
* All annotation information from a class that is annotated with
|
||||
* the annotation com.sun.oracle.objects.annotations.ScriptClass.
|
||||
*
|
||||
*/
|
||||
public final class ScriptClassInfo {
|
||||
// descriptots for various annotations
|
||||
static final String SCRIPT_CLASS_ANNO_DESC = Type.getDescriptor(ScriptClass.class);
|
||||
static final String CONSTRUCTOR_ANNO_DESC = Type.getDescriptor(Constructor.class);
|
||||
static final String FUNCTION_ANNO_DESC = Type.getDescriptor(Function.class);
|
||||
static final String GETTER_ANNO_DESC = Type.getDescriptor(Getter.class);
|
||||
static final String SETTER_ANNO_DESC = Type.getDescriptor(Setter.class);
|
||||
static final String PROPERTY_ANNO_DESC = Type.getDescriptor(Property.class);
|
||||
static final String WHERE_ENUM_DESC = Type.getDescriptor(Where.class);
|
||||
static final String SPECIALIZED_FUNCTION = Type.getDescriptor(SpecializedFunction.class);
|
||||
static final String SPECIALIZED_CONSTRUCTOR = Type.getDescriptor(SpecializedConstructor.class);
|
||||
|
||||
static final Map<String, Kind> annotations = new HashMap<>();
|
||||
|
||||
static {
|
||||
annotations.put(SCRIPT_CLASS_ANNO_DESC, Kind.SCRIPT_CLASS);
|
||||
annotations.put(FUNCTION_ANNO_DESC, Kind.FUNCTION);
|
||||
annotations.put(CONSTRUCTOR_ANNO_DESC, Kind.CONSTRUCTOR);
|
||||
annotations.put(GETTER_ANNO_DESC, Kind.GETTER);
|
||||
annotations.put(SETTER_ANNO_DESC, Kind.SETTER);
|
||||
annotations.put(PROPERTY_ANNO_DESC, Kind.PROPERTY);
|
||||
annotations.put(SPECIALIZED_FUNCTION, Kind.SPECIALIZED_FUNCTION);
|
||||
annotations.put(SPECIALIZED_CONSTRUCTOR, Kind.SPECIALIZED_CONSTRUCTOR);
|
||||
}
|
||||
|
||||
// name of the script class
|
||||
private String name;
|
||||
// member info for script properties
|
||||
private List<MemberInfo> members = Collections.emptyList();
|
||||
// java class name that is annotated with @ScriptClass
|
||||
private String javaName;
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the members
|
||||
*/
|
||||
public List<MemberInfo> getMembers() {
|
||||
return Collections.unmodifiableList(members);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param members the members to set
|
||||
*/
|
||||
public void setMembers(final List<MemberInfo> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
MemberInfo getConstructor() {
|
||||
for (final MemberInfo memInfo : members) {
|
||||
if (memInfo.getKind() == Kind.CONSTRUCTOR) {
|
||||
return memInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<MemberInfo> getSpecializedConstructors() {
|
||||
final List<MemberInfo> res = new LinkedList<>();
|
||||
for (final MemberInfo memInfo : members) {
|
||||
if (memInfo.getKind() == Kind.SPECIALIZED_CONSTRUCTOR) {
|
||||
res.add(memInfo);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int getPrototypeMemberCount() {
|
||||
int count = 0;
|
||||
for (final MemberInfo memInfo : members) {
|
||||
if (memInfo.getWhere() == Where.PROTOTYPE || memInfo.isConstructor()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int getConstructorMemberCount() {
|
||||
int count = 0;
|
||||
for (final MemberInfo memInfo : members) {
|
||||
if (memInfo.getWhere() == Where.CONSTRUCTOR) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int getInstancePropertyCount() {
|
||||
int count = 0;
|
||||
for (final MemberInfo memInfo : members) {
|
||||
if (memInfo.getWhere() == Where.INSTANCE) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
MemberInfo find(final String findJavaName, final String findJavaDesc, final int findAccess) {
|
||||
for (final MemberInfo memInfo : members) {
|
||||
if (memInfo.getJavaName().equals(findJavaName) &&
|
||||
memInfo.getJavaDesc().equals(findJavaDesc) &&
|
||||
memInfo.getJavaAccess() == findAccess) {
|
||||
return memInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<MemberInfo> findSpecializations(final String methodName) {
|
||||
final List<MemberInfo> res = new LinkedList<>();
|
||||
for (final MemberInfo memInfo : members) {
|
||||
if (memInfo.getName().equals(methodName) &&
|
||||
memInfo.getKind() == Kind.SPECIALIZED_FUNCTION) {
|
||||
res.add(memInfo);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
MemberInfo findSetter(final MemberInfo getter) {
|
||||
assert getter.getKind() == Kind.GETTER : "getter expected";
|
||||
final String getterName = getter.getName();
|
||||
final Where getterWhere = getter.getWhere();
|
||||
for (final MemberInfo memInfo : members) {
|
||||
if (memInfo.getKind() == Kind.SETTER &&
|
||||
getterName.equals(memInfo.getName()) &&
|
||||
getterWhere == memInfo.getWhere()) {
|
||||
return memInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the javaName
|
||||
*/
|
||||
public String getJavaName() {
|
||||
return javaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param javaName the javaName to set
|
||||
*/
|
||||
void setJavaName(final String javaName) {
|
||||
this.javaName = javaName;
|
||||
}
|
||||
|
||||
String getConstructorClassName() {
|
||||
return getJavaName() + StringConstants.CONSTRUCTOR_SUFFIX;
|
||||
}
|
||||
|
||||
String getPrototypeClassName() {
|
||||
return getJavaName() + StringConstants.PROTOTYPE_SUFFIX;
|
||||
}
|
||||
|
||||
void verify() {
|
||||
boolean constructorSeen = false;
|
||||
for (final MemberInfo memInfo : getMembers()) {
|
||||
if (memInfo.isConstructor()) {
|
||||
if (constructorSeen) {
|
||||
error("more than @Constructor method");
|
||||
}
|
||||
constructorSeen = true;
|
||||
}
|
||||
try {
|
||||
memInfo.verify();
|
||||
} catch (final Exception e) {
|
||||
error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void error(final String msg) throws RuntimeException {
|
||||
throw new RuntimeException(javaName + " : " + msg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.SCRIPT_CLASS_ANNO_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.WHERE_ENUM_DESC;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.nashorn.internal.objects.annotations.Where;
|
||||
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
|
||||
|
||||
/**
|
||||
* This class collects all @ScriptClass and other annotation information from a
|
||||
* compiled .class file. Enforces that @Function/@Getter/@Setter/@Constructor
|
||||
* methods are declared to be 'static'.
|
||||
*/
|
||||
public class ScriptClassInfoCollector extends ClassVisitor {
|
||||
private String scriptClassName;
|
||||
private List<MemberInfo> scriptMembers;
|
||||
private String javaClassName;
|
||||
|
||||
ScriptClassInfoCollector(final ClassVisitor visitor) {
|
||||
super(Opcodes.ASM4, visitor);
|
||||
}
|
||||
|
||||
ScriptClassInfoCollector() {
|
||||
this(new NullVisitor());
|
||||
}
|
||||
|
||||
private void addScriptMember(final MemberInfo memInfo) {
|
||||
if (scriptMembers == null) {
|
||||
scriptMembers = new ArrayList<>();
|
||||
}
|
||||
scriptMembers.add(memInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name, final String signature,
|
||||
final String superName, final String[] interfaces) {
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
javaClassName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
|
||||
final AnnotationVisitor delegateAV = super.visitAnnotation(desc, visible);
|
||||
if (SCRIPT_CLASS_ANNO_DESC.equals(desc)) {
|
||||
return new AnnotationVisitor(Opcodes.ASM4, delegateAV) {
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
if ("value".equals(name)) {
|
||||
scriptClassName = (String) value;
|
||||
}
|
||||
super.visit(name, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return delegateAV;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(final int fieldAccess, final String fieldName, final String fieldDesc, final String signature, final Object value) {
|
||||
final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc, signature, value);
|
||||
|
||||
return new FieldVisitor(Opcodes.ASM4, delegateFV) {
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
final AnnotationVisitor delegateAV = super.visitAnnotation(descriptor, visible);
|
||||
|
||||
if (ScriptClassInfo.PROPERTY_ANNO_DESC.equals(descriptor)) {
|
||||
final MemberInfo memInfo = new MemberInfo();
|
||||
|
||||
memInfo.setKind(Kind.PROPERTY);
|
||||
memInfo.setJavaName(fieldName);
|
||||
memInfo.setJavaDesc(fieldDesc);
|
||||
memInfo.setJavaAccess(fieldAccess);
|
||||
|
||||
if ((fieldAccess & Opcodes.ACC_STATIC) != 0) {
|
||||
memInfo.setValue(value);
|
||||
}
|
||||
|
||||
addScriptMember(memInfo);
|
||||
|
||||
return new AnnotationVisitor(Opcodes.ASM4, delegateAV) {
|
||||
// These could be "null" if values are not suppiled,
|
||||
// in which case we have to use the default values.
|
||||
private String name;
|
||||
private Integer attributes;
|
||||
private String clazz = "";
|
||||
private Where where;
|
||||
|
||||
@Override
|
||||
public void visit(final String annotationName, final Object annotationValue) {
|
||||
switch (annotationName) {
|
||||
case "name":
|
||||
this.name = (String) annotationValue;
|
||||
break;
|
||||
case "attributes":
|
||||
this.attributes = (Integer) annotationValue;
|
||||
break;
|
||||
case "clazz":
|
||||
this.clazz = (annotationValue == null) ? "" : annotationValue.toString();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
super.visit(annotationName, annotationValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(final String enumName, final String desc, final String enumValue) {
|
||||
if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) {
|
||||
this.where = Where.valueOf(enumValue);
|
||||
}
|
||||
super.visitEnum(enumName, desc, enumValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
memInfo.setName(name == null ? fieldName : name);
|
||||
memInfo.setAttributes(attributes == null
|
||||
? MemberInfo.DEFAULT_ATTRIBUTES : attributes);
|
||||
clazz = clazz.replace('.', '/');
|
||||
memInfo.setInitClass(clazz);
|
||||
memInfo.setWhere(where == null? Where.INSTANCE : where);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return delegateAV;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void error(final String javaName, final String javaDesc, final String msg) {
|
||||
throw new RuntimeException(scriptClassName + "." + javaName + javaDesc + " : " + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int methodAccess, final String methodName,
|
||||
final String methodDesc, final String signature, final String[] exceptions) {
|
||||
|
||||
final MethodVisitor delegateMV = super.visitMethod(methodAccess, methodName, methodDesc,
|
||||
signature, exceptions);
|
||||
|
||||
return new MethodVisitor(Opcodes.ASM4, delegateMV) {
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
final AnnotationVisitor delegateAV = super.visitAnnotation(descriptor, visible);
|
||||
final Kind annoKind = ScriptClassInfo.annotations.get(descriptor);
|
||||
|
||||
if (annoKind != null) {
|
||||
if ((methodAccess & Opcodes.ACC_STATIC) == 0) {
|
||||
error(methodName, methodDesc, "nasgen method annotations cannot be on instance methods");
|
||||
}
|
||||
|
||||
final MemberInfo memInfo = new MemberInfo();
|
||||
|
||||
memInfo.setKind(annoKind);
|
||||
memInfo.setJavaName(methodName);
|
||||
memInfo.setJavaDesc(methodDesc);
|
||||
memInfo.setJavaAccess(methodAccess);
|
||||
|
||||
addScriptMember(memInfo);
|
||||
|
||||
return new AnnotationVisitor(Opcodes.ASM4, delegateAV) {
|
||||
// These could be "null" if values are not suppiled,
|
||||
// in which case we have to use the default values.
|
||||
private String name;
|
||||
private Integer attributes;
|
||||
private Integer arity;
|
||||
private Where where;
|
||||
|
||||
@Override
|
||||
public void visit(final String annotationName, final Object annotationValue) {
|
||||
switch (annotationName) {
|
||||
case "name":
|
||||
this.name = (String)annotationValue;
|
||||
break;
|
||||
case "attributes":
|
||||
this.attributes = (Integer)annotationValue;
|
||||
break;
|
||||
case "arity":
|
||||
this.arity = (Integer)annotationValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
super.visit(annotationName, annotationValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(final String enumName, final String desc, final String enumValue) {
|
||||
if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) {
|
||||
this.where = Where.valueOf(enumValue);
|
||||
}
|
||||
super.visitEnum(enumName, desc, enumValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
|
||||
if (memInfo.getKind() == Kind.CONSTRUCTOR) {
|
||||
memInfo.setName(name == null ? scriptClassName : name);
|
||||
} else {
|
||||
memInfo.setName(name == null ? methodName : name);
|
||||
}
|
||||
memInfo.setAttributes(attributes == null ? MemberInfo.DEFAULT_ATTRIBUTES : attributes);
|
||||
|
||||
memInfo.setArity((arity == null)? MemberInfo.DEFAULT_ARITY : arity);
|
||||
if (where == null) {
|
||||
// by default @Getter/@Setter belongs to INSTANCE
|
||||
// @Function belong to PROTOTYPE.
|
||||
switch (memInfo.getKind()) {
|
||||
case GETTER:
|
||||
case SETTER:
|
||||
where = Where.INSTANCE;
|
||||
break;
|
||||
case SPECIALIZED_CONSTRUCTOR:
|
||||
case CONSTRUCTOR:
|
||||
where = Where.CONSTRUCTOR;
|
||||
break;
|
||||
case FUNCTION:
|
||||
where = Where.PROTOTYPE;
|
||||
break;
|
||||
case SPECIALIZED_FUNCTION:
|
||||
//TODO is this correct
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
memInfo.setWhere(where);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return delegateAV;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ScriptClassInfo getScriptClassInfo() {
|
||||
ScriptClassInfo sci = null;
|
||||
if (scriptClassName != null) {
|
||||
sci = new ScriptClassInfo();
|
||||
sci.setName(scriptClassName);
|
||||
if (scriptMembers == null) {
|
||||
scriptMembers = Collections.emptyList();
|
||||
}
|
||||
sci.setMembers(scriptMembers);
|
||||
sci.setJavaName(javaClassName);
|
||||
}
|
||||
return sci;
|
||||
}
|
||||
|
||||
/**
|
||||
* External entry point for ScriptClassInfoCollector if invoked from the command line
|
||||
* @param args argument vector, args contains a class for which to collect info
|
||||
* @throws IOException if there were problems parsing args or class
|
||||
*/
|
||||
public static void main(final String[] args) throws IOException {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " <class>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
args[0] = args[0].replace('.', '/');
|
||||
final ScriptClassInfoCollector scic = new ScriptClassInfoCollector();
|
||||
try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(args[0] + ".class"))) {
|
||||
final ClassReader reader = new ClassReader(bis);
|
||||
reader.accept(scic, 0);
|
||||
}
|
||||
final ScriptClassInfo sci = scic.getScriptClassInfo();
|
||||
final PrintStream out = System.out;
|
||||
if (sci != null) {
|
||||
out.println("script class: " + sci.getName());
|
||||
out.println("===================================");
|
||||
for (final MemberInfo memInfo : sci.getMembers()) {
|
||||
out.println("kind : " + memInfo.getKind());
|
||||
out.println("name : " + memInfo.getName());
|
||||
out.println("attributes: " + memInfo.getAttributes());
|
||||
out.println("javaName: " + memInfo.getJavaName());
|
||||
out.println("javaDesc: " + memInfo.getJavaDesc());
|
||||
out.println("where: " + memInfo.getWhere());
|
||||
out.println("=====================================");
|
||||
}
|
||||
} else {
|
||||
out.println(args[0] + " is not a @ScriptClass");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
|
||||
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.NEW;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.$CLINIT$;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
|
||||
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Attribute;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
|
||||
import jdk.nashorn.internal.objects.annotations.Where;
|
||||
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
|
||||
|
||||
/**
|
||||
* This class instruments the java class annotated with @ScriptClass.
|
||||
*
|
||||
* Changes done are:
|
||||
*
|
||||
* 1) remove all jdk.nashorn.internal.objects.annotations.* annotations.
|
||||
* 2) static final @Property fields stay here. Other @Property fields moved to
|
||||
* respective classes depending on 'where' value of annotation.
|
||||
* 2) add "Map" type static field named "$map".
|
||||
* 3) add static initializer block to initialize map.
|
||||
*/
|
||||
|
||||
public class ScriptClassInstrumentor extends ClassVisitor {
|
||||
private final ScriptClassInfo scriptClassInfo;
|
||||
private final int memberCount;
|
||||
private boolean staticInitFound;
|
||||
|
||||
ScriptClassInstrumentor(final ClassVisitor visitor, final ScriptClassInfo sci) {
|
||||
super(Opcodes.ASM4, visitor);
|
||||
if (sci == null) {
|
||||
throw new IllegalArgumentException("Null ScriptClassInfo, is the class annotated?");
|
||||
}
|
||||
this.scriptClassInfo = sci;
|
||||
this.memberCount = scriptClassInfo.getInstancePropertyCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
|
||||
if (ScriptClassInfo.annotations.containsKey(desc)) {
|
||||
// ignore @ScriptClass
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(final int fieldAccess, final String fieldName,
|
||||
final String fieldDesc, final String signature, final Object value) {
|
||||
final MemberInfo memInfo = scriptClassInfo.find(fieldName, fieldDesc, fieldAccess);
|
||||
if (memInfo != null && memInfo.getKind() == Kind.PROPERTY &&
|
||||
memInfo.getWhere() != Where.INSTANCE && !memInfo.isStaticFinal()) {
|
||||
// non-instance @Property fields - these have to go elsewhere unless 'static final'
|
||||
return null;
|
||||
}
|
||||
|
||||
final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc,
|
||||
signature, value);
|
||||
return new FieldVisitor(Opcodes.ASM4, delegateFV) {
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
|
||||
if (ScriptClassInfo.annotations.containsKey(desc)) {
|
||||
// ignore script field annotations
|
||||
return null;
|
||||
}
|
||||
|
||||
return fv.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
fv.visitAttribute(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
fv.visitEnd();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int methodAccess, final String methodName,
|
||||
final String methodDesc, final String signature, final String[] exceptions) {
|
||||
|
||||
final boolean isConstructor = INIT.equals(methodName);
|
||||
final boolean isStaticInit = CLINIT.equals(methodName);
|
||||
|
||||
if (isStaticInit) {
|
||||
staticInitFound = true;
|
||||
}
|
||||
|
||||
final MethodGenerator delegateMV = new MethodGenerator(super.visitMethod(methodAccess, methodName, methodDesc,
|
||||
signature, exceptions), methodAccess, methodName, methodDesc);
|
||||
|
||||
return new MethodVisitor(Opcodes.ASM4, delegateMV) {
|
||||
@Override
|
||||
public void visitInsn(final int opcode) {
|
||||
// call $clinit$ just before return from <clinit>
|
||||
if (isStaticInit && opcode == RETURN) {
|
||||
super.visitMethodInsn(INVOKESTATIC, scriptClassInfo.getJavaName(),
|
||||
$CLINIT$, DEFAULT_INIT_DESC);
|
||||
}
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
|
||||
if (isConstructor && opcode == INVOKESPECIAL &&
|
||||
INIT.equals(name) && SCRIPTOBJECT_TYPE.equals(owner)) {
|
||||
super.visitFieldInsn(GETSTATIC, scriptClassInfo.getJavaName(),
|
||||
MAP_FIELD_NAME, MAP_DESC);
|
||||
super.visitMethodInsn(INVOKESPECIAL, SCRIPTOBJECT_TYPE, INIT,
|
||||
SCRIPTOBJECT_INIT_DESC);
|
||||
|
||||
if (memberCount > 0) {
|
||||
// initialize @Property fields if needed
|
||||
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (memInfo.isInstanceProperty() && !memInfo.getInitClass().isEmpty()) {
|
||||
final String clazz = memInfo.getInitClass();
|
||||
super.visitVarInsn(ALOAD, 0);
|
||||
super.visitTypeInsn(NEW, clazz);
|
||||
super.visitInsn(DUP);
|
||||
super.visitMethodInsn(INVOKESPECIAL, clazz,
|
||||
INIT, DEFAULT_INIT_DESC);
|
||||
super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(),
|
||||
memInfo.getJavaName(), memInfo.getJavaDesc());
|
||||
}
|
||||
|
||||
if (memInfo.isInstanceFunction()) {
|
||||
super.visitVarInsn(ALOAD, 0);
|
||||
ClassGenerator.newFunction(delegateMV, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName()));
|
||||
super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(),
|
||||
memInfo.getJavaName(), OBJECT_DESC);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
|
||||
if (ScriptClassInfo.annotations.containsKey(desc)) {
|
||||
// ignore script method annotations
|
||||
return null;
|
||||
}
|
||||
return super.visitAnnotation(desc, visible);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
emitFields();
|
||||
emitStaticInitializer();
|
||||
emitGettersSetters();
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
private void emitFields() {
|
||||
// introduce "Function" type instance fields for each
|
||||
// instance @Function in script class info
|
||||
final String className = scriptClassInfo.getJavaName();
|
||||
for (MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (memInfo.isInstanceFunction()) {
|
||||
ClassGenerator.addFunctionField(cv, memInfo.getJavaName());
|
||||
memInfo = (MemberInfo)memInfo.clone();
|
||||
memInfo.setJavaDesc(OBJECT_DESC);
|
||||
ClassGenerator.addGetter(cv, className, memInfo);
|
||||
ClassGenerator.addSetter(cv, className, memInfo);
|
||||
}
|
||||
}
|
||||
ClassGenerator.addMapField(this);
|
||||
}
|
||||
|
||||
void emitGettersSetters() {
|
||||
if (memberCount > 0) {
|
||||
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
final String className = scriptClassInfo.getJavaName();
|
||||
if (memInfo.isInstanceProperty()) {
|
||||
ClassGenerator.addGetter(cv, className, memInfo);
|
||||
if (! memInfo.isFinal()) {
|
||||
ClassGenerator.addSetter(cv, className, memInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void emitStaticInitializer() {
|
||||
final String className = scriptClassInfo.getJavaName();
|
||||
if (! staticInitFound) {
|
||||
// no user written <clinit> and so create one
|
||||
final MethodVisitor mv = ClassGenerator.makeStaticInitializer(this);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(Short.MAX_VALUE, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
// Now generate $clinit$
|
||||
final MethodGenerator mi = ClassGenerator.makeStaticInitializer(this, $CLINIT$);
|
||||
ClassGenerator.emitStaticInitPrefix(mi, className);
|
||||
if (memberCount > 0) {
|
||||
for (final MemberInfo memInfo : scriptClassInfo.getMembers()) {
|
||||
if (memInfo.isInstanceProperty() || memInfo.isInstanceFunction()) {
|
||||
ClassGenerator.linkerAddGetterSetter(mi, className, memInfo);
|
||||
} else if (memInfo.isInstanceGetter()) {
|
||||
final MemberInfo setter = scriptClassInfo.findSetter(memInfo);
|
||||
ClassGenerator.linkerAddGetterSetter(mi, className, memInfo, setter);
|
||||
}
|
||||
}
|
||||
}
|
||||
ClassGenerator.emitStaticInitSuffix(mi, className);
|
||||
}
|
||||
|
||||
/**
|
||||
* External entry point for ScriptClassInfoCollector if run from the command line
|
||||
*
|
||||
* @param args arguments - one argument is needed, the name of the class to collect info from
|
||||
*
|
||||
* @throws IOException if there are problems reading class
|
||||
*/
|
||||
public static void main(final String[] args) throws IOException {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " <class>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
final String fileName = args[0].replace('.', '/') + ".class";
|
||||
final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(fileName);
|
||||
if (sci == null) {
|
||||
System.err.println("No @ScriptClass in " + fileName);
|
||||
System.exit(2);
|
||||
throw new AssertionError(); //guard against warning that sci is null below
|
||||
}
|
||||
|
||||
try {
|
||||
sci.verify();
|
||||
} catch (final Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
System.exit(3);
|
||||
}
|
||||
|
||||
final ClassWriter writer = ClassGenerator.makeClassWriter();
|
||||
try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) {
|
||||
final ClassReader reader = new ClassReader(bis);
|
||||
final CheckClassAdapter checker = new CheckClassAdapter(writer);
|
||||
final ScriptClassInstrumentor instr = new ScriptClassInstrumentor(checker, sci);
|
||||
reader.accept(instr, 0);
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(fileName)) {
|
||||
fos.write(writer.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.tools.nasgen;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Method;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.nashorn.internal.objects.PrototypeObject;
|
||||
import jdk.nashorn.internal.objects.ScriptFunctionImpl;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.linker.Lookup;
|
||||
|
||||
/**
|
||||
* String constants used for code generation/instrumentation.
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
public interface StringConstants {
|
||||
static final Type TYPE_METHOD = Type.getType(Method.class);
|
||||
static final Type TYPE_METHODHANDLE = Type.getType(MethodHandle.class);
|
||||
static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class);
|
||||
static final Type TYPE_OBJECT = Type.getType(Object.class);
|
||||
static final Type TYPE_CLASS = Type.getType(Class.class);
|
||||
static final Type TYPE_STRING = Type.getType(String.class);
|
||||
|
||||
// Nashorn types
|
||||
static final Type TYPE_LOOKUP = Type.getType(Lookup.class);
|
||||
static final Type TYPE_PROPERTYMAP = Type.getType(PropertyMap.class);
|
||||
static final Type TYPE_PROTOTYPEOBJECT = Type.getType(PrototypeObject.class);
|
||||
static final Type TYPE_SCRIPTFUNCTION = Type.getType(ScriptFunction.class);
|
||||
static final Type TYPE_SCRIPTFUNCTIONIMPL = Type.getType(ScriptFunctionImpl.class);
|
||||
static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class);
|
||||
|
||||
static final String PROTOTYPE = "prototype";
|
||||
static final String PROTOTYPE_SUFFIX = "$Prototype";
|
||||
static final String CONSTRUCTOR_SUFFIX = "$Constructor";
|
||||
// This field name is known to Nashorn runtime (Context).
|
||||
// Synchronize the name change, if needed at all.
|
||||
static final String MAP_FIELD_NAME = "$nasgenmap$";
|
||||
static final String $CLINIT$ = "$clinit$";
|
||||
static final String CLINIT = "<clinit>";
|
||||
static final String INIT = "<init>";
|
||||
static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE);
|
||||
|
||||
static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP);
|
||||
|
||||
static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName();
|
||||
|
||||
static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName();
|
||||
static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor();
|
||||
static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class);
|
||||
|
||||
static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName();
|
||||
static final String SCRIPTFUNCTIONIMPL_TYPE = TYPE_SCRIPTFUNCTIONIMPL.getInternalName();
|
||||
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION = "makeFunction";
|
||||
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC =
|
||||
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE);
|
||||
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC =
|
||||
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
|
||||
|
||||
static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 =
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
|
||||
static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 =
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY);
|
||||
static final String SCRIPTFUNCTION_SETARITY = "setArity";
|
||||
static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
|
||||
static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName();
|
||||
static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor";
|
||||
static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT);
|
||||
static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName();
|
||||
static final String MAP_TYPE = TYPE_PROPERTYMAP.getInternalName();
|
||||
static final String MAP_DESC = TYPE_PROPERTYMAP.getDescriptor();
|
||||
static final String MAP_NEWMAP = "newMap";
|
||||
static final String MAP_NEWMAP_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_CLASS);
|
||||
static final String MAP_DUPLICATE = "duplicate";
|
||||
static final String MAP_DUPLICATE_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP);
|
||||
static final String MAP_SETFLAGS = "setFlags";
|
||||
static final String LOOKUP_TYPE = TYPE_LOOKUP.getInternalName();
|
||||
static final String LOOKUP_GETMETHOD = "getMethod";
|
||||
static final String LOOKUP_NEWPROPERTY = "newProperty";
|
||||
static final String LOOKUP_NEWPROPERTY_DESC =
|
||||
Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_PROPERTYMAP, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE);
|
||||
static final String GETTER_PREFIX = "G$";
|
||||
static final String SETTER_PREFIX = "S$";
|
||||
|
||||
// ScriptObject.getClassName() method.
|
||||
static final String GET_CLASS_NAME = "getClassName";
|
||||
static final String GET_CLASS_NAME_DESC = Type.getMethodDescriptor(TYPE_STRING);
|
||||
}
|
||||
445
nashorn/docs/DEVELOPER_README
Normal file
445
nashorn/docs/DEVELOPER_README
Normal file
@ -0,0 +1,445 @@
|
||||
This document describes system properties that are used for internal
|
||||
debugging and instrumentation purposes, along with the system loggers,
|
||||
which are used for the same thing.
|
||||
|
||||
This document is intended as a developer resource, and it is not
|
||||
needed as Nashorn documentation for normal usage. Flags and system
|
||||
properties described herein are subject to change without notice.
|
||||
|
||||
=====================================
|
||||
1. System properties used internally
|
||||
=====================================
|
||||
|
||||
This documentation of the system property flags assume that the
|
||||
default value of the flag is false, unless otherwise specified.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: -Dnashorn.callsiteaccess.debug
|
||||
|
||||
See the description of the access logger below. This flag is
|
||||
equivalent to enabling the access logger with "info" level.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: -Dnashorn.compiler.ints.disable
|
||||
|
||||
This flag prevents ints and longs (non double values) from being used
|
||||
for any primitive representation in the lowered IR. This is default
|
||||
false, i.e Lower will attempt to use integer variables as long as it
|
||||
can. For example, var x = 17 would try to use x as an integer, unless
|
||||
other operations occur later that require coercion to wider type, for
|
||||
example x *= 17.1;
|
||||
|
||||
|
||||
SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic
|
||||
|
||||
Arithmetic operations in Nashorn (except bitwise ones) typically
|
||||
coerce the operands to doubles (as per the JavaScript spec). To switch
|
||||
this off and remain in integer mode, for example for "var x = a&b; var
|
||||
y = c&d; var z = x*y;", use this flag. This will force the
|
||||
multiplication of variables that are ints to be done with the IMUL
|
||||
bytecode and the result "z" to become an int.
|
||||
|
||||
WARNING: Note that is is experimental only to ensure that type support
|
||||
exists for all primitive types. The generated code is unsound. This
|
||||
will be the case until we do optimizations based on it. There is a CR
|
||||
in Nashorn to do better range analysis, and ensure that this is only
|
||||
done where the operation can't overflow into a wider type. Currently
|
||||
no overflow checking is done, so at the moment, until range analysis
|
||||
has been completed, this option is turned off.
|
||||
|
||||
We've experimented by using int arithmetic for everything and putting
|
||||
overflow checks afterwards, which would recompute the operation with
|
||||
the correct precision, but have yet to find a configuration where this
|
||||
is faster than just using doubles directly, even if the int operation
|
||||
does not overflow. Getting access to a JVM intrinsic that does branch
|
||||
on overflow would probably alleviate this.
|
||||
|
||||
There is also a problem with this optimistic approach if the symbol
|
||||
happens to reside in a local variable slot in the bytecode, as those
|
||||
are strongly typed. Then we would need to split large sections of
|
||||
control flow, so this is probably not the right way to go, while range
|
||||
analysis is. There is a large difference between integer bytecode
|
||||
without overflow checks and double bytecode. The former is
|
||||
significantly faster.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: -Dnashorn.codegen.debug, -Dnashorn.codegen.debug.trace=<x>
|
||||
|
||||
See the description of the codegen logger below.
|
||||
|
||||
|
||||
SYSTEM_PROPERTY: -Dnashorn.fields.debug
|
||||
|
||||
See the description on the fields logger below.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: -Dnashorn.fields.dual
|
||||
|
||||
When this property is true, Nashorn will attempt to use primitive
|
||||
fields for AccessorProperties (currently just AccessorProperties, not
|
||||
spill properties). Memory footprint for script objects will increase,
|
||||
as we need to maintain both a primitive field (a long) as well as an
|
||||
Object field for the property value. Ints are represented as the 32
|
||||
low bits of the long fields. Doubles are represented as the
|
||||
doubleToLongBits of their value. This way a single field can be used
|
||||
for all primitive types. Packing and unpacking doubles to their bit
|
||||
representation is intrinsified by the JVM and extremely fast.
|
||||
|
||||
While dual fields in theory runs significantly faster than Object
|
||||
fields due to reduction of boxing and memory allocation overhead,
|
||||
there is still work to be done to make this a general purpose
|
||||
solution. Research is ongoing.
|
||||
|
||||
In the future, this might complement or be replaced by experimental
|
||||
feature sun.misc.TaggedArray, which has been discussed on the mlvm
|
||||
mailing list. TaggedArrays are basically a way to share data space
|
||||
between primitives and references, and have the GC understand this.
|
||||
|
||||
As long as only primitive values are written to the fields and enough
|
||||
type information exists to make sure that any reads don't have to be
|
||||
uselessly boxed and unboxed, this is significantly faster than the
|
||||
standard "Objects only" approach that currently is the default. See
|
||||
test/examples/dual-fields-micro.js for an example that runs twice as
|
||||
fast with dual fields as without them. Here, the compiler, can
|
||||
determine that we are dealing with numbers only throughout the entire
|
||||
property life span of the properties involved.
|
||||
|
||||
If a "real" object (not a boxed primitive) is written to a field that
|
||||
has a primitive representation, its callsite is relinked and an Object
|
||||
field is used forevermore for that particular field in that
|
||||
PropertyMap and its children, even if primitives are later assigned to
|
||||
it.
|
||||
|
||||
As the amount of compile time type information is very small in a
|
||||
dynamic language like JavaScript, it is frequently the case that
|
||||
something has to be treated as an object, because we don't know any
|
||||
better. In reality though, it is often a boxed primitive is stored to
|
||||
an AccessorProperty. The fastest way to handle this soundly is to use
|
||||
a callsite typecheck and avoid blowing the field up to an Object. We
|
||||
never revert object fields to primitives. Ping-pong:ing back and forth
|
||||
between primitive representation and Object representation would cause
|
||||
fatal performance overhead, so this is not an option.
|
||||
|
||||
For a general application the dual fields approach is still slower
|
||||
than objects only fields in some places, about the same in most cases,
|
||||
and significantly faster in very few. This is due the program using
|
||||
primitives, but we still can't prove it. For example "local_var a =
|
||||
call(); field = a;" may very well write a double to the field, but the
|
||||
compiler dare not guess a double type if field is a local variable,
|
||||
due to bytecode variables being strongly typed and later non
|
||||
interchangeable. To get around this, the entire method would have to
|
||||
be replaced and a continuation retained to restart from. We believe
|
||||
that the next steps we should go through are instead:
|
||||
|
||||
1) Implement method specialization based on callsite, as it's quite
|
||||
frequently the case that numbers are passed around, but currently our
|
||||
function nodes just have object types visible to the compiler. For
|
||||
example "var b = 17; func(a,b,17)" is an example where two parameters
|
||||
can be specialized, but the main version of func might also be called
|
||||
from another callsite with func(x,y,"string").
|
||||
|
||||
2) This requires lazy jitting as the functions have to be specialized
|
||||
per callsite.
|
||||
|
||||
Even though "function square(x) { return x*x }" might look like a
|
||||
trivial function that can always only take doubles, this is not
|
||||
true. Someone might have overridden the valueOf for x so that the
|
||||
toNumber coercion has side effects. To fulfil JavaScript semantics,
|
||||
the coercion has to run twice for both terms of the multiplication
|
||||
even if they are the same object. This means that call site
|
||||
specialization is necessary, not parameter specialization on the form
|
||||
"function square(x) { var xd = (double)x; return xd*xd; }", as one
|
||||
might first think.
|
||||
|
||||
Generating a method specialization for any variant of a function that
|
||||
we can determine by types at compile time is a combinatorial explosion
|
||||
of byte code (try it e.g. on all the variants of am3 in the Octane
|
||||
benchmark crypto.js). Thus, this needs to be lazy
|
||||
|
||||
3) Possibly optimistic callsite writes, something on the form
|
||||
|
||||
x = y; //x is a field known to be a primitive. y is only an object as
|
||||
far as we can tell
|
||||
|
||||
turns into
|
||||
|
||||
try {
|
||||
x = (int)y;
|
||||
} catch (X is not an integer field right now | ClassCastException e) {
|
||||
x = y;
|
||||
}
|
||||
|
||||
Mini POC shows that this is the key to a lot of dual field performance
|
||||
in seemingly trivial micros where one unknown object, in reality
|
||||
actually a primitive, foils it for us. Very common pattern. Once we
|
||||
are "all primitives", dual fields runs a lot faster than Object fields
|
||||
only.
|
||||
|
||||
We still have to deal with objects vs primitives for local bytecode
|
||||
slots, possibly through code copying and versioning.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=<x>
|
||||
|
||||
When this property is set, creation and manipulation of any symbol
|
||||
named "x" will show information about when the compiler changes its
|
||||
type assumption, bytecode local variable slot assignment and other
|
||||
data. This is useful if, for example, a symbol shows up as an Object,
|
||||
when you believe it should be a primitive. Usually there is an
|
||||
explanation for this, for example that it exists in the global scope
|
||||
and type analysis has to be more conservative. In that case, the stack
|
||||
trace upon type change to object will usually tell us why.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.lexer.xmlliterals
|
||||
|
||||
If this property it set, it means that the Lexer should attempt to
|
||||
parse XML literals, which would otherwise generate syntax
|
||||
errors. Warning: there are currently no unit tests for this
|
||||
functionality.
|
||||
|
||||
XML literals, when this is enabled, end up as standard LiteralNodes in
|
||||
the IR.
|
||||
|
||||
|
||||
SYSTEM_PROPERTY: nashorn.debug
|
||||
|
||||
If this property is set to true, Nashorn runs in Debug mode. Debug
|
||||
mode is slightly slower, as for example statistics counters are enabled
|
||||
during the run. Debug mode makes available a NativeDebug instance
|
||||
called "Debug" in the global space that can be used to print property
|
||||
maps and layout for script objects, as well as a "dumpCounters" method
|
||||
that will print the current values of the previously mentioned stats
|
||||
counters.
|
||||
|
||||
These functions currently exists for Debug:
|
||||
|
||||
"map" - print(Debug.map(x)) will dump the PropertyMap for object x to
|
||||
stdout (currently there also exist functions called "embedX", where X
|
||||
is a value from 0 to 3, that will dump the contents of the embed pool
|
||||
for the first spill properties in any script object and "spill", that
|
||||
will dump the contents of the growing spill pool of spill properties
|
||||
in any script object. This is of course subject to change without
|
||||
notice, should we change the script object layout.
|
||||
|
||||
"methodHandle" - this method returns the method handle that is used
|
||||
for invoking a particular script function.
|
||||
|
||||
"identical" - this method compares two script objects for reference
|
||||
equality. It is a == Java comparison
|
||||
|
||||
"dumpCounters" - will dump the debug counters' current values to
|
||||
stdout.
|
||||
|
||||
Currently we count number of ScriptObjects in the system, number of
|
||||
Scope objects in the system, number of ScriptObject listeners added,
|
||||
removed and dead (without references).
|
||||
|
||||
We also count number of ScriptFunctions, ScriptFunction invocations
|
||||
and ScriptFunction allocations.
|
||||
|
||||
Furthermore we count PropertyMap statistics: how many property maps
|
||||
exist, how many times were property maps cloned, how many times did
|
||||
the property map history cache hit, prevent new allocations, how many
|
||||
prototype invalidations were done, how many time the property map
|
||||
proto cache hit.
|
||||
|
||||
Finally we count callsite misses on a per callsite bases, which occur
|
||||
when a callsite has to be relinked, due to a previous assumption of
|
||||
object layout being invalidated.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.methodhandles.debug,
|
||||
nashorn.methodhandles.debug=create
|
||||
|
||||
If this property is enabled, each MethodHandle related call that uses
|
||||
the java.lang.invoke package gets its MethodHandle intercepted and an
|
||||
instrumentation printout of arguments and return value appended to
|
||||
it. This shows exactly which method handles are executed and from
|
||||
where. (Also MethodTypes and SwitchPoints). This can be augmented with
|
||||
more information, for example, instance count, by subclassing or
|
||||
further extending the TraceMethodHandleFactory implementation in
|
||||
MethodHandleFactory.java.
|
||||
|
||||
If the property is specialized with "=create" as its option,
|
||||
instrumentation will be shown for method handles upon creation time
|
||||
rather than at runtime usage.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.methodhandles.debug.stacktrace
|
||||
|
||||
This does the same as nashorn.methodhandles.debug, but when enabled
|
||||
also dumps the stack trace for every instrumented method handle
|
||||
operation. Warning: This is enormously verbose, but provides a pretty
|
||||
decent "grep:able" picture of where the calls are coming from.
|
||||
|
||||
See the description of the codegen logger below for a more verbose
|
||||
description of this option
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.scriptfunction.specialization.disable
|
||||
|
||||
There are several "fast path" implementations of constructors and
|
||||
functions in the NativeObject classes that, in their original form,
|
||||
take a variable amount of arguments. Said functions are also declared
|
||||
to take Object parameters in their original form, as this is what the
|
||||
JavaScript specification mandates.
|
||||
|
||||
However, we often know quite a lot more at a callsite of one of these
|
||||
functions. For example, Math.min is called with a fixed number (2) of
|
||||
integer arguments. The overhead of boxing these ints to Objects and
|
||||
folding them into an Object array for the generic varargs Math.min
|
||||
function is an order of magnitude slower than calling a specialized
|
||||
implementation of Math.min that takes two integers. Specialized
|
||||
functions and constructors are identified by the tag
|
||||
@SpecializedFunction and @SpecializedConstructor in the Nashorn
|
||||
code. The linker will link in the most appropriate (narrowest types,
|
||||
right number of types and least number of arguments) specialization if
|
||||
specializations are available.
|
||||
|
||||
Every ScriptFunction may carry specializations that the linker can
|
||||
choose from. This framework will likely be extended for user defined
|
||||
functions. The compiler can often infer enough parameter type info
|
||||
from callsites for in order to generate simpler versions with less
|
||||
generic Object types. This feature depends on future lazy jitting, as
|
||||
there tend to be many calls to user defined functions, some where the
|
||||
callsite can be specialized, some where we mostly see object
|
||||
parameters even at the callsite.
|
||||
|
||||
If this system property is set to true, the linker will not attempt to
|
||||
use any specialized function or constructor for native objects, but
|
||||
just call the generic one.
|
||||
|
||||
|
||||
SYSTEM PROPERTY: nashorn.tcs.miss.samplePercent=<x>
|
||||
|
||||
When running with the trace callsite option (-tcs), Nashorn will count
|
||||
and instrument any callsite misses that require relinking. As the
|
||||
number of relinks is large and usually produces a lot of output, this
|
||||
system property can be used to constrain the percentage of misses that
|
||||
should be logged. Typically this is set to 1 or 5 (percent). 1% is the
|
||||
default value.
|
||||
|
||||
|
||||
SYSTEM_PROPERTY: nashorn.profilefile=<filename>
|
||||
|
||||
When running with the profile callsite options (-pcs), Nashorn will
|
||||
dump profiling data for all callsites to stderr as a shutdown hook. To
|
||||
instead redirect this to a file, specify the path to the file using
|
||||
this system property.
|
||||
|
||||
|
||||
===============
|
||||
2. The loggers.
|
||||
===============
|
||||
|
||||
The Nashorn loggers can be used to print per-module or per-subsystem
|
||||
debug information with different levels of verbosity. The loggers for
|
||||
a given subsystem are available are enabled by using
|
||||
|
||||
--log=<systemname>[:<level>]
|
||||
|
||||
on the command line.
|
||||
|
||||
Here <systemname> identifies the name of the subsystem to be logged
|
||||
and the optional colon and level argument is a standard
|
||||
java.util.logging.Level name (severe, warning, info, config, fine,
|
||||
finer, finest). If the level is left out for a particular subsystem,
|
||||
it defaults to "info". Any log message logged as the level or a level
|
||||
that is more important will be output to stderr by the logger.
|
||||
|
||||
Several loggers can be enabled by a single command line option, by
|
||||
putting a comma after each subsystem/level tuple (or each subsystem if
|
||||
level is unspecified). The --log option can also be given multiple
|
||||
times on the same command line, with the same effect.
|
||||
|
||||
For example: --log=codegen,fields:finest is equivalent to
|
||||
--log=codegen:info --log=fields:finest
|
||||
|
||||
The subsystems that currently support logging are:
|
||||
|
||||
|
||||
* compiler
|
||||
|
||||
The compiler is in charge of turning source code and function nodes
|
||||
into byte code, and installs the classes into a class loader
|
||||
controlled from the Context. Log messages are, for example, about
|
||||
things like new compile units being allocated. The compiler has global
|
||||
settings that all the tiers of codegen (e.g. Lower and CodeGenerator)
|
||||
use.
|
||||
|
||||
|
||||
* codegen
|
||||
|
||||
The code generator is the emitter stage of the code pipeline, and
|
||||
turns the lowest tier of a FunctionNode into bytecode. Codegen logging
|
||||
shows byte codes as they are being emitted, line number information
|
||||
and jumps. It also shows the contents of the bytecode stack prior to
|
||||
each instruction being emitted. This is a good debugging aid. For
|
||||
example:
|
||||
|
||||
[codegen] #41 line:2 (f)_afc824e
|
||||
[codegen] #42 load symbol x slot=2
|
||||
[codegen] #43 {1:O} load int 0
|
||||
[codegen] #44 {2:I O} dynamic_runtime_call GT:ZOI_I args=2 returnType=boolean
|
||||
[codegen] #45 signature (Ljava/lang/Object;I)Z
|
||||
[codegen] #46 {1:Z} ifeq ternary_false_5402fe28
|
||||
[codegen] #47 load symbol x slot=2
|
||||
[codegen] #48 {1:O} goto ternary_exit_107c1f2f
|
||||
[codegen] #49 ternary_false_5402fe28
|
||||
[codegen] #50 load symbol x slot=2
|
||||
[codegen] #51 {1:O} convert object -> double
|
||||
[codegen] #52 {1:D} neg
|
||||
[codegen] #53 {1:D} convert double -> object
|
||||
[codegen] #54 {1:O} ternary_exit_107c1f2f
|
||||
[codegen] #55 {1:O} return object
|
||||
|
||||
shows a ternary node being generated for the sequence "return x > 0 ?
|
||||
x : -x"
|
||||
|
||||
The first number on the log line is a unique monotonically increasing
|
||||
emission id per bytecode. There is no guarantee this is the same id
|
||||
between runs. depending on non deterministic code
|
||||
execution/compilation, but for small applications it usually is. If
|
||||
the system variable -Dnashorn.codegen.debug.trace=<x> is set, where x
|
||||
is a bytecode emission id, a stack trace will be shown as the
|
||||
particular bytecode is about to be emitted. This can be a quick way to
|
||||
determine where it comes from without attaching the debugger. "Who
|
||||
generated that neg?"
|
||||
|
||||
The --log=codegen option is equivalent to setting the system variable
|
||||
"nashorn.codegen.debug" to true.
|
||||
|
||||
|
||||
* lower
|
||||
|
||||
The lowering annotates a FunctionNode with symbols for each identifier
|
||||
and transforms high level constructs into lower level ones, that the
|
||||
CodeGenerator consumes.
|
||||
|
||||
Lower logging typically outputs things like post pass actions,
|
||||
insertions of casts because symbol types have been changed and type
|
||||
specialization information. Currently very little info is generated by
|
||||
this logger. This will probably change.
|
||||
|
||||
|
||||
* access
|
||||
|
||||
The --log=access option is equivalent to setting the system variable
|
||||
"nashorn.callsiteaccess.debug" to true. There are several levels of
|
||||
the access logger, usually the default level "info" is enough
|
||||
|
||||
It is very simple to create your own logger. Use the DebugLogger class
|
||||
and give the subsystem name as a constructor argument.
|
||||
|
||||
|
||||
* fields
|
||||
|
||||
The --log=fields option (at info level) is equivalent to setting the
|
||||
system variable "nashorn.fields.debug" to true. At the info level it
|
||||
will only show info about type assumptions that were invalidated. If
|
||||
the level is set to finest, it will also trace every AccessorProperty
|
||||
getter and setter in the program, show arguments, return values
|
||||
etc. It will also show the internal representation of respective field
|
||||
(Object in the normal case, unless running with the dual field
|
||||
representation)
|
||||
90
nashorn/docs/genshelldoc.js
Normal file
90
nashorn/docs/genshelldoc.js
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate HTML documentation for shell tool. Re-run this tool to regenerate
|
||||
* html doc when you change options.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* jjs -scripting genshelldoc.js > shell.html
|
||||
*/
|
||||
|
||||
var Options = Packages.jdk.nashorn.internal.runtime.options.Options;
|
||||
var title = "Nashorn command line shell tool";
|
||||
|
||||
print(<<PREFIX
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
${title}
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Usage</h1>
|
||||
<p>
|
||||
<code>
|
||||
<b>jjs <options> <script-files> [ -- <script-arguments> ]</b>
|
||||
</code>
|
||||
</p>
|
||||
|
||||
<h1>${title} options</h1>
|
||||
|
||||
<table border="0">
|
||||
<tr>
|
||||
<th>name</th>
|
||||
<th>type</th>
|
||||
<th>default</th>
|
||||
<th>description</th>
|
||||
</tr>
|
||||
PREFIX);
|
||||
|
||||
for each (opt in Options.validOptions) {
|
||||
|
||||
var isTimezone = (opt.type == "timezone");
|
||||
var defValue = opt.defaultValue;
|
||||
if (defValue == null) {
|
||||
defValue = "<none>";
|
||||
}
|
||||
|
||||
if (isTimezone) {
|
||||
// don't output current user's timezone
|
||||
defValue = "<default-timezone>"
|
||||
}
|
||||
|
||||
print(<<ROW
|
||||
<tr>
|
||||
<td><b>${opt.name} ${opt.shortName == null? "" : opt.shortName}</b></td>
|
||||
<td>${opt.type}</td>
|
||||
<td>${defValue}</td>
|
||||
<td>${opt.description}</td>
|
||||
</tr>
|
||||
ROW);
|
||||
|
||||
}
|
||||
|
||||
print(<<SUFFIX
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
SUFFIX);
|
||||
224
nashorn/make/Makefile
Normal file
224
nashorn/make/Makefile
Normal file
@ -0,0 +1,224 @@
|
||||
#
|
||||
# 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. 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 nashorn: wrapper around Ant build.xml file
|
||||
|
||||
#
|
||||
# On Solaris, the standard 'make' utility will not work with these makefiles.
|
||||
# This little rule is only understood by Solaris make, and is harmless
|
||||
# when seen by the GNU make tool. If using Solaris make, this causes the
|
||||
# make command to fail.
|
||||
#
|
||||
SUN_MAKE_TEST:sh = @echo "ERROR: PLEASE USE GNU VERSION OF MAKE"; exit 33
|
||||
|
||||
#
|
||||
# Minimal platform defs
|
||||
# Need FullPath because we can't rely on gnumake abspath, until we use v3.81
|
||||
#
|
||||
|
||||
SYSTEM_UNAME := $(shell uname)
|
||||
|
||||
# Where is unwanted output to be delivered?
|
||||
# On Windows, MKS uses the special file "NUL", cygwin uses the customary unix file.
|
||||
ifeq ($(SYSTEM_UNAME), Windows_NT)
|
||||
DEV_NULL = NUL
|
||||
else
|
||||
DEV_NULL = /dev/null
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring CYGWIN,$(SYSTEM_UNAME)))
|
||||
USING_CYGWIN = true
|
||||
endif
|
||||
|
||||
ifdef USING_CYGWIN
|
||||
define FullPath
|
||||
$(shell cygpath -a -s -m $1 2> $(DEV_NULL))
|
||||
endef
|
||||
else
|
||||
define FullPath
|
||||
$(shell cd $1 2> $(DEV_NULL) && pwd)
|
||||
endef
|
||||
endif
|
||||
|
||||
#
|
||||
# Makefile args
|
||||
#
|
||||
|
||||
ifdef QUIET
|
||||
ANT_OPTIONS += -quiet
|
||||
endif
|
||||
|
||||
ifdef VERBOSE
|
||||
ANT_OPTIONS += -verbose -debug
|
||||
endif
|
||||
|
||||
ifdef JDK_VERSION
|
||||
ANT_OPTIONS += -Djdk.version=$(JDK_VERSION)
|
||||
endif
|
||||
|
||||
ifdef FULL_VERSION
|
||||
ANT_OPTIONS += -Dfull.version='$(FULL_VERSION)' # will contain spaces
|
||||
endif
|
||||
|
||||
ifdef MILESTONE
|
||||
ifneq ($(MILESTONE),fcs)
|
||||
ANT_OPTIONS += -Dmilestone=$(MILESTONE)
|
||||
else
|
||||
ANT_OPTIONS += -Drelease=$(JDK_VERSION)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef BUILD_NUMBER
|
||||
ANT_OPTIONS += -Dbuild.number=$(BUILD_NUMBER)
|
||||
else
|
||||
ifdef JDK_BUILD_NUMBER
|
||||
ANT_OPTIONS += -Dbuild.number=$(JDK_BUILD_NUMBER)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(VARIANT), DBG)
|
||||
ANT_OPTIONS += -Djavac.debug=true
|
||||
else
|
||||
ifeq ($(VARIANT), OPT)
|
||||
ANT_OPTIONS += -Djavac.debug=false
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG_CLASSFILES), true)
|
||||
ANT_OPTIONS += -Djavac.debug=true
|
||||
ANT_OPTIONS += -Ddebug.classfiles=true
|
||||
endif
|
||||
|
||||
# Note: jdk/make/common/Defs.gmk uses LANGUAGE_VERSION (-source NN)
|
||||
# and the somewhat misnamed CLASS_VERSION (-target NN)
|
||||
ifdef TARGET_CLASS_VERSION
|
||||
ANT_OPTIONS += -Djavac.target=$(TARGET_CLASS_VERSION)
|
||||
else
|
||||
ifdef JAVAC_TARGET_ARG
|
||||
ANT_OPTIONS += -Djavac.target=$(JAVAC_TARGET_ARG)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOURCE_LANGUAGE_VERSION
|
||||
ANT_OPTIONS += -Djavac.source=$(SOURCE_LANGUAGE_VERSION)
|
||||
else
|
||||
ifdef JAVAC_SOURCE_ARG
|
||||
ANT_OPTIONS += -Djavac.source=$(JAVAC_SOURCE_ARG)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef ALT_BOOTDIR
|
||||
ANT_OPTIONS += -Dboot.java.home=$(ALT_BOOTDIR)
|
||||
ANT_JAVA_HOME = JAVA_HOME=$(ALT_BOOTDIR)
|
||||
endif
|
||||
|
||||
# To facilitate bootstrapping, much of langtools can be compiled with (just)
|
||||
# a boot JDK. However, some source files need to be compiled against
|
||||
# new JDK API. In a bootstrap build, an import JDK may not be available,
|
||||
# so build.xml can also build against the source files in a jdk repo,
|
||||
# in which case it will automatically generate stub files for the new JDK API.
|
||||
ifdef JDK_TOPDIR
|
||||
ANT_OPTIONS += -Dimport.jdk=$(JDK_TOPDIR)
|
||||
else
|
||||
ifdef ALT_JDK_TOPDIR
|
||||
ANT_OPTIONS += -Dimport.jdk=$(ALT_JDK_TOPDIR)
|
||||
else
|
||||
ifdef ALT_JDK_IMPORT_PATH
|
||||
ANT_OPTIONS += -Dimport.jdk=$(ALT_JDK_IMPORT_PATH)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef ALT_OUTPUTDIR
|
||||
OUTPUTDIR = $(ALT_OUTPUTDIR)
|
||||
ANT_OPTIONS += -Dbuild.dir=$(ALT_OUTPUTDIR)/build
|
||||
ANT_OPTIONS += -Ddist.dir=$(ALT_OUTPUTDIR)/dist
|
||||
else
|
||||
OUTPUTDIR = ..
|
||||
endif
|
||||
#ABS_OUTPUTDIR = $(abspath $(OUTPUTDIR))
|
||||
ABS_OUTPUTDIR = $(call FullPath,$(OUTPUTDIR))
|
||||
|
||||
ANT_TMPDIR = $(ABS_OUTPUTDIR)/build/ant-tmp
|
||||
ANT_OPTS = ANT_OPTS=-Djava.io.tmpdir='$(ANT_TMPDIR)'
|
||||
|
||||
ifdef FINDBUGS_HOME
|
||||
ANT_OPTIONS += -Dfindbugs.home=$(FINDBUGS_HOME)
|
||||
endif
|
||||
|
||||
ifdef ANT_HOME
|
||||
ANT = $(ANT_HOME)/bin/ant
|
||||
ifneq ($(shell test -x $(ANT) && echo OK), OK)
|
||||
$(error $(ANT) not found -- please update ANT_HOME)
|
||||
endif
|
||||
else
|
||||
ANT = ant
|
||||
ifneq ($(shell test -x "`which $(ANT)`" && echo OK), OK)
|
||||
$(error 'ant' not found -- please set ANT_HOME or put 'ant' on your PATH)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Default target and expected 'do everything' target
|
||||
# comments docs to avoid too many ASM warnings
|
||||
# all: test docs
|
||||
|
||||
all: test
|
||||
|
||||
# Standard make clobber target
|
||||
clobber: clean
|
||||
|
||||
# All ant targets of interest
|
||||
ANT_TARGETS = clean jar javadoc shelldoc docs test test262 test262parallel # for now
|
||||
|
||||
# Create diagnostics log (careful, ant 1.8.0 -diagnostics always does an exit 1)
|
||||
$(OUTPUTDIR)/build/ant-diagnostics.log:
|
||||
@mkdir -p $(OUTPUTDIR)/build $(ANT_TMPDIR)
|
||||
@$(RM) $@
|
||||
$(ANT_JAVA_HOME) $(ANT_OPTS) $(ANT) -diagnostics > $@ ; \
|
||||
$(ANT_JAVA_HOME) $(ANT_OPTS) $(ANT) -version >> $@
|
||||
|
||||
# Create a make target for each
|
||||
$(ANT_TARGETS): $(OUTPUTDIR)/build/ant-diagnostics.log
|
||||
@ mkdir -p $(OUTPUTDIR)/build $(ANT_TMPDIR)
|
||||
$(ANT_JAVA_HOME) $(ANT_OPTS) $(ANT) $(ANT_OPTIONS) $@
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#
|
||||
# Targets for Oracle's internal JPRT build system
|
||||
|
||||
CD = cd
|
||||
ZIP = zip
|
||||
|
||||
JPRT_ARCHIVE_BUNDLE=$(ABS_OUTPUTDIR)/$(JPRT_BUILD_FLAVOR)-bundle.zip
|
||||
|
||||
jprt_build_product jprt_build_debug jprt_build_fastdebug: all
|
||||
( $(CD) $(OUTPUTDIR) && \
|
||||
$(ZIP) -q -r $(JPRT_ARCHIVE_BUNDLE) build dist )
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
# Declare these phony (not filenames)
|
||||
.PHONY: $(ANT_TARGETS) all clobber \
|
||||
jprt_build_product jprt_build_debug jprt_build_fastdebug
|
||||
348
nashorn/make/build-benchmark.xml
Normal file
348
nashorn/make/build-benchmark.xml
Normal file
@ -0,0 +1,348 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project name="nashorn-benchmarks" default="all" basedir="..">
|
||||
|
||||
<target name="octane-init" depends="jar">
|
||||
<fileset id="octane-set"
|
||||
dir="${octane-test-sys-prop.test.js.roots}"
|
||||
excludes="${octane-test-sys-prop.test.js.exclude.list}">
|
||||
<include name="**/*.js"/>
|
||||
</fileset>
|
||||
<pathconvert pathsep=" " property="octane-tests" refid="octane-set"/>
|
||||
<property name="extra-arg" value=""/>
|
||||
</target>
|
||||
|
||||
<!-- box2d -->
|
||||
<target name="box2d-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/box2d.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-box2d" depends="jar, box2d-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-box2d-v8" depends="jar, box2d-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-box2d-rhino" depends="jar, box2d-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- code-load -->
|
||||
<target name="code-load-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/code-load.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-code-load" depends="jar, code-load-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-code-load-v8" depends="jar, code-load-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-code-load-rhino" depends="jar, code-load-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- crypto -->
|
||||
<target name="crypto-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/crypto.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-crypto" depends="jar, crypto-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-crypto-v8" depends="jar, crypto-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-crypto-rhino" depends="jar, crypto-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- deltablue -->
|
||||
<target name="deltablue-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/deltablue.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-deltablue" depends="jar, deltablue-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-deltablue-v8" depends="jar, deltablue-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-deltablue-rhino" depends="jar, deltablue-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- earley-boyer -->
|
||||
<target name="earley-boyer-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/earley-boyer.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-earley-boyer" depends="jar, earley-boyer-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-earley-boyer-v8" depends="jar, earley-boyer-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-earley-boyer-rhino" depends="jar, earley-boyer-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- gbemu -->
|
||||
<target name="gbemu-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/gbemu.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-gbemu" depends="jar, gbemu-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-gbemu-v8" depends="jar, gbemu-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-gbemu-rhino" depends="jar, gbemu-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- navier-stokes -->
|
||||
<target name="navier-stokes-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/navier-stokes.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-navier-stokes" depends="jar, navier-stokes-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-navier-stokes-v8" depends="jar, navier-stokes-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-navier-stokes-rhino" depends="jar, navier-stokes-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- pdfjs -->
|
||||
<target name="pdfjs-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/pdfjs.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-pdfjs" depends="jar, pdfjs-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-pdfjs-v8" depends="jar, pdfjs-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-pdfjs-rhino" depends="jar, pdfjs-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- raytrace -->
|
||||
<target name="raytrace-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/raytrace.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-raytrace" depends="jar, raytrace-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-raytrace-v8" depends="jar, raytrace-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-raytrace-rhino" depends="jar, raytrace-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<!-- regexp -->
|
||||
<target name="regexp-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/regexp.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-regexp" depends="jar, regexp-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-regexp-octane-v8" depends="jar, regexp-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-regexp-rhino" depends="jar, regexp-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- splay -->
|
||||
<target name="splay-init">
|
||||
<property name="octane-tests" value="${octane-test-sys-prop.test.js.roots}/splay.js"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-splay" depends="jar, splay-init, octane-verbose">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-splay-v8" depends="jar, splay-init, octane-verbose">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-splay-rhino" depends="jar, splay-init, octane-verbose">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<target name="octane-verbose">
|
||||
<property name="extra-arg" value="--verbose"/>
|
||||
</target>
|
||||
|
||||
<!-- run octane benchmarks using Nashorn as runtime -->
|
||||
<target name="octane" depends="octane-init">
|
||||
<antcall target="run-octane"/>
|
||||
</target>
|
||||
|
||||
<!-- run octane benchmarks using octane as runtime -->
|
||||
<target name="octane-v8" depends="octane-init">
|
||||
<antcall target="run-octane-v8"/>
|
||||
</target>
|
||||
|
||||
<!-- run octane benchmarks using Rhino as runtime -->
|
||||
<target name="octane-rhino" depends="octane-init">
|
||||
<antcall target="run-octane-rhino"/>
|
||||
</target>
|
||||
|
||||
<target name="run-octane">
|
||||
<java classname="${nashorn.shell.tool}"
|
||||
classpath="${run.test.classpath}"
|
||||
fork="true"
|
||||
dir=".">
|
||||
<jvmarg line="${boot.class.path}"/>
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs.octane}"/>
|
||||
<arg value="${octane-test-sys-prop.test.js.framework}"/>
|
||||
<arg value="--"/>
|
||||
<arg value="${octane-tests}"/>
|
||||
<arg value="--runtime"/>
|
||||
<arg value="Nashorn"/>
|
||||
<arg value="--verbose"/>
|
||||
<arg value="--iterations 8"/>
|
||||
<arg value="${extra-arg}"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="run-octane-v8">
|
||||
<exec executable="${v8.shell}">
|
||||
<arg value="${octane-test-sys-prop.test.js.framework}"/>
|
||||
<arg value="--"/>
|
||||
<arg value="${octane-tests}"/>
|
||||
<arg value="--runtime"/>
|
||||
<arg value="v8"/>
|
||||
<arg value="--verbose"/>
|
||||
<arg value="--iterations 8"/>
|
||||
<arg value="${extra-arg}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="run-octane-rhino">
|
||||
<java jar="${rhino.jar}"
|
||||
classpath="${run.test.classpath}"
|
||||
fork="true"
|
||||
dir=".">
|
||||
<jvmarg line="${boot.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs.octane}"/>
|
||||
<arg value="${octane-test-sys-prop.test.js.framework}"/>
|
||||
<arg value="${octane-tests}"/>
|
||||
<arg value="--runtime"/>
|
||||
<arg value="Rhino"/>
|
||||
<arg value="--verbose"/>
|
||||
<arg value="--iterations 8"/>
|
||||
<arg value="${extra-arg}"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<!-- run octane with all known runtimes for comparison -->
|
||||
<target name="octane-all" depends="octane, octane-v8, octane-rhino">
|
||||
<exec executable="${v8.shell}">
|
||||
<arg value="${octane-test-sys-prop.test.js.framework}"/>
|
||||
<arg value="${octane-tests}/"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="sunspider-init" depends="jar">
|
||||
<fileset id="sunspider-set"
|
||||
dir="${sunspider-test-sys-prop.test.js.roots}"
|
||||
excludes="${sunspider-test-sys-prop.test.js.exclude.list}">
|
||||
<include name="**/*.js"/>
|
||||
</fileset>
|
||||
<pathconvert pathsep=" " property="sunspider-tests" refid="sunspider-set"/>
|
||||
</target>
|
||||
|
||||
<!-- run sunspider with Nashorn -->
|
||||
<target name="sunspider" depends="sunspider-init">
|
||||
<java classname="${nashorn.shell.tool}"
|
||||
classpath="${run.test.classpath}"
|
||||
fork="true"
|
||||
dir=".">
|
||||
<jvmarg line="${boot.class.path}"/>
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<arg value="-timezone=PST"/>
|
||||
<arg value="--class-cache-size=50"/>
|
||||
<arg value="${sunspider-test-sys-prop.test.js.framework}"/>
|
||||
<arg value="--"/>
|
||||
<arg value="${sunspider-tests}/"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<!-- run sunspider with v8 -->
|
||||
<target name="sunspider-v8" depends="sunspider-init">
|
||||
<exec executable="${v8.shell}">
|
||||
<arg value="${sunspider-test-sys-prop.test.js.framework}"/>
|
||||
<arg value="--"/>
|
||||
<arg value="${sunspider-tests}/"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- run sunspider with Rhino -->
|
||||
<target name="sunspider-rhino" depends="sunspider-init">
|
||||
<java jar="${rhino.jar}"
|
||||
classpath="${run.test.classpath}"
|
||||
fork="true"
|
||||
dir=".">
|
||||
<jvmarg line="${boot.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<arg value="${sunspider-test-sys-prop.test.js.framework}"/>
|
||||
<arg value="${sunspider-tests}/"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
</project>
|
||||
86
nashorn/make/build-nasgen.xml
Normal file
86
nashorn/make/build-nasgen.xml
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project name="build-nasgen" default="run-nasgen" basedir="..">
|
||||
<description>Builds and runs nasgen.</description>
|
||||
<import file="build.xml"/>
|
||||
|
||||
<target name="build-nasgen" depends="compile-asm">
|
||||
<ant inheritAll="false" dir="${basedir}/buildtools/nasgen"
|
||||
antfile="build.xml" target="jar"/>
|
||||
</target>
|
||||
|
||||
<target name="run-nasgen" depends="build-nasgen">
|
||||
<java classname="${nasgen.tool}" fork="true" failonerror="true">
|
||||
<classpath>
|
||||
<pathelement location="${basedir}/jcov2/lib/jcov_j2se_rt.jar"/>
|
||||
<pathelement location="${basedir}/buildtools/nasgen/dist/nasgen.jar"/>
|
||||
<pathelement path="${basedir}/build/classes"/>
|
||||
</classpath>
|
||||
<arg value="${basedir}/build/classes"/>
|
||||
<arg value="jdk.nashorn.internal.objects"/>
|
||||
<arg value="${basedir}/build/classes"/>
|
||||
</java>
|
||||
|
||||
<move todir="${basedir}/build/classes/jdk/nashorn/internal/objects">
|
||||
<fileset dir="${basedir}/build/classes/jdk/nashorn/internal/objects"/>
|
||||
<mapper type="glob" from="*.class" to="*.clazz"/>
|
||||
</move>
|
||||
</target>
|
||||
|
||||
<target name="run-nasgen-eclipse">
|
||||
<mkdir dir="${basedir}/build/eclipse/.nasgentmp"/>
|
||||
|
||||
<java classname="jdk.nashorn.internal.tools.nasgen.Main" fork="true" failonerror="true">
|
||||
<classpath>
|
||||
<pathelement location="${basedir}/buildtools/nasgen/dist/nasgen.jar"/>
|
||||
<pathelement path="${basedir}/build/eclipse"/>
|
||||
</classpath>
|
||||
<arg value="${basedir}/build/eclipse"/>
|
||||
<arg value="jdk.nashorn.internal.objects"/>
|
||||
<arg value="${basedir}/build/eclipse/.nasgentmp"/>
|
||||
</java>
|
||||
|
||||
<move todir="${basedir}/build/eclipse/jdk/nashorn/internal/objects">
|
||||
<fileset dir="${basedir}/build/eclipse/.nasgentmp/jdk/nashorn/internal/objects">
|
||||
<include name="*.class"/>
|
||||
</fileset>
|
||||
<mapper type="glob" from="*.class" to="*.clazz"/>
|
||||
</move>
|
||||
|
||||
<delete includeemptydirs="true"><fileset dir="${basedir}/build/eclipse/.nasgentmp" includes="**"/></delete>
|
||||
|
||||
<copy todir="${basedir}/build/eclipse/jdk/nashorn/internal/objects" preservelastmodified="true">
|
||||
<fileset dir="${basedir}/build/eclipse/jdk/nashorn/internal/objects">
|
||||
<include name="**/*.class"/>
|
||||
</fileset>
|
||||
<mapper type="glob" from="*.class" to="*.clazz"/>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="clean-nasgen">
|
||||
<ant inheritAll="false" dir="${basedir}/buildtools/nasgen"
|
||||
antfile="build.xml" target="clean"/>
|
||||
</target>
|
||||
|
||||
</project>
|
||||
355
nashorn/make/build.xml
Normal file
355
nashorn/make/build.xml
Normal file
@ -0,0 +1,355 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project name="nashorn" default="all" basedir="..">
|
||||
<import file="build-nasgen.xml"/>
|
||||
<import file="build-benchmark.xml"/>
|
||||
|
||||
<target name="init">
|
||||
<loadproperties srcFile="make/project.properties"/>
|
||||
<path id="nashorn.ext.path">
|
||||
<pathelement location="${dist.dir}"/>
|
||||
</path>
|
||||
<property name="ext.class.path" value="-Djava.ext.dirs="${toString:nashorn.ext.path}""/>
|
||||
</target>
|
||||
|
||||
<target name="prepare" depends="init">
|
||||
<mkdir dir="${build.dir}"/>
|
||||
<mkdir dir="${build.classes.dir}"/>
|
||||
<mkdir dir="${build.classes.dir}/META-INF/services"/>
|
||||
<mkdir dir="${build.test.classes.dir}"/>
|
||||
<mkdir dir="${dist.dir}"/>
|
||||
<mkdir dir="${dist.javadoc.dir}"/>
|
||||
<!-- check if JDK already has ASM classes -->
|
||||
<available property="asm.available" classname="jdk.internal.org.objectweb.asm.Type"/>
|
||||
<!-- check if testng.jar is avaiable -->
|
||||
<available property="testng.available" file="${file.reference.testng.jar}"/>
|
||||
</target>
|
||||
|
||||
<target name="clean" depends="init, clean-nasgen">
|
||||
<delete includeemptydirs="true">
|
||||
<fileset dir="${build.dir}" excludes="${dynalink.dir.name}/**/*" erroronmissingdir="false"/>
|
||||
</delete>
|
||||
<delete dir="${dist.dir}"/>
|
||||
</target>
|
||||
|
||||
<target name="clean-dynalink">
|
||||
<delete dir="${dynalink.dir}"/>
|
||||
</target>
|
||||
|
||||
<target name="clean-all" depends="clean-dynalink, clean">
|
||||
<delete dir="${build.dir}"/>
|
||||
</target>
|
||||
|
||||
<!-- do it only if ASM is not available -->
|
||||
<target name="compile-asm" depends="prepare" unless="asm.available">
|
||||
<javac srcdir="${asm.src.dir}"
|
||||
destdir="${build.classes.dir}"
|
||||
excludes="**/optimizer/* **/xml/* **/attrs/*"
|
||||
source="${javac.source}"
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
encoding="${javac.encoding}"
|
||||
includeantruntime="false"/>
|
||||
</target>
|
||||
|
||||
<target name="check-dynalink-uptodate" depends="init">
|
||||
<property name="versioned.dynalink.jar" value="${dynalink.dir}/dynalink-${dynalink.jar.version}.jar"/>
|
||||
<condition property="dynalink.uptodate">
|
||||
<and>
|
||||
<available file="${versioned.dynalink.jar}"/>
|
||||
<filesmatch file1="${versioned.dynalink.jar}" file2="${dynalink.jar}"/>
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<target name="get-dynalink" depends="check-dynalink-uptodate" unless="dynalink.uptodate">
|
||||
<mkdir dir="${dynalink.dir}"/>
|
||||
<!-- Delete previous snapshots, if any -->
|
||||
<delete>
|
||||
<fileset dir="${dynalink.dir}" includes="*"/>
|
||||
</delete>
|
||||
<property name="dynalink.download.base.url" value="http://oss.sonatype.org/content/repositories/${dynalink.version.type}s/org/dynalang/dynalink/${dynalink.version}/dynalink-${dynalink.jar.version}"/>
|
||||
<get src="${dynalink.download.base.url}.jar" dest="${versioned.dynalink.jar}" usetimestamp="true"/>
|
||||
<get src="${dynalink.download.base.url}-sources.jar" dest="${dynalink.dir}/dynalink-sources.jar" usetimestamp="true"/>
|
||||
<copy file="${versioned.dynalink.jar}" tofile="${dynalink.jar}" overwrite="true"/>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="compile-asm, get-dynalink" description="Compiles nashorn">
|
||||
<javac srcdir="${src.dir}"
|
||||
destdir="${build.classes.dir}"
|
||||
classpath="${javac.classpath}"
|
||||
source="${javac.source}"
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
encoding="${javac.encoding}"
|
||||
includeantruntime="false">
|
||||
<compilerarg value="-Xlint:unchecked"/>
|
||||
<compilerarg value="-Xlint:deprecation"/>
|
||||
<compilerarg value="-XDignore.symbol.file"/>
|
||||
</javac>
|
||||
<copy todir="${build.classes.dir}/META-INF/services">
|
||||
<fileset dir="${meta.inf.dir}/services/"/>
|
||||
</copy>
|
||||
<copy todir="${build.classes.dir}/jdk/nashorn/api/scripting/resources">
|
||||
<fileset dir="${src.dir}/jdk/nashorn/api/scripting/resources/"/>
|
||||
</copy>
|
||||
<copy todir="${build.classes.dir}/jdk/nashorn/internal/runtime/resources">
|
||||
<fileset dir="${src.dir}/jdk/nashorn/internal/runtime/resources/"/>
|
||||
</copy>
|
||||
<copy todir="${build.classes.dir}/jdk/nashorn/tools/resources">
|
||||
<fileset dir="${src.dir}/jdk/nashorn/tools/resources/"/>
|
||||
</copy>
|
||||
<echo message="full=${nashorn.fullversion}" file="${build.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties"/>
|
||||
<echo file="${build.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties" append="true">${line.separator}</echo>
|
||||
<echo message="release=${nashorn.version}" file="${build.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties" append="true"/>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile, run-nasgen" description="Creates nashorn.jar">
|
||||
<jar jarfile="${dist.jar}" manifest="${meta.inf.dir}/MANIFEST.MF" index="true" filesetmanifest="merge">
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
<zipfileset src="${dynalink.jar}"/>
|
||||
<manifest>
|
||||
<attribute name="Archiver-Version" value="n/a"/>
|
||||
<attribute name="Build-Jdk" value="${java.runtime.version}"/>
|
||||
<attribute name="Built-By" value="n/a"/>
|
||||
<attribute name="Created-By" value="Ant jar task"/>
|
||||
<section name="jdk/nashorn/">
|
||||
<attribute name="Implementation-Title" value="${nashorn.product.name}"/>
|
||||
<attribute name="Implementation-Version" value="${nashorn.version}"/>
|
||||
</section>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="javadoc" depends="compile-asm">
|
||||
<javadoc destdir="${dist.javadoc.dir}" private="yes" use="yes" overview="src/overview.html" windowtitle="${nashorn.product.name} ${nashorn.version}">
|
||||
<classpath>
|
||||
<pathelement location="${build.classes.dir}"/>
|
||||
<pathelement location="${dynalink.jar}"/>
|
||||
</classpath>
|
||||
<fileset dir="${src.dir}" includes="**/*.java"/>
|
||||
<link href="http://docs.oracle.com/javase/7/docs/api"/>
|
||||
<link href="http://szegedi.github.com/dynalink/0.4/javadoc"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
<!-- generate shell.html for shell tool documentation -->
|
||||
<target name="shelldoc" depends="jar">
|
||||
<java classname="${nashorn.shell.tool}" dir="${basedir}" output="${dist.dir}/shell.html" failonerror="true" fork="true">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<arg value="-scripting"/>
|
||||
<arg value="docs/genshelldoc.js"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<!-- generate all docs -->
|
||||
<target name="docs" depends="javadoc, shelldoc"/>
|
||||
|
||||
<!-- create .zip and .tar.gz for nashorn binaries and scripts. -->
|
||||
<target name="dist" depends="jar">
|
||||
<zip destfile="${build.zip}" basedir=".."
|
||||
excludes="nashorn/bin/*.sh" includes="nashorn/bin/** nashorn/dist/**"/>
|
||||
<tar destfile="${build.gzip}" basedir=".." compression="gzip"
|
||||
excludes="nashorn/bin/*.sh" includes="nashorn/bin/** nashorn/dist/**"/>
|
||||
</target>
|
||||
|
||||
<target name="compile-test" depends="compile, run-nasgen" if="testng.available">
|
||||
<!-- testng task -->
|
||||
<taskdef name="testng" classname="org.testng.TestNGAntTask"
|
||||
classpath="${file.reference.testng.jar}"/>
|
||||
|
||||
<javac srcdir="${test.src.dir}"
|
||||
destdir="${build.test.classes.dir}"
|
||||
classpath="${javac.test.classpath}"
|
||||
source="${javac.source}"
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
encoding="${javac.encoding}"
|
||||
includeantruntime="false"/>
|
||||
</target>
|
||||
|
||||
<target name="generate-policy-file">
|
||||
<!-- Generating nashorn.policy file -->
|
||||
<echo message="grant codeBase "file:/${basedir}/dist/nashorn.jar" {" file="${build.dir}/nashorn.policy"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
|
||||
<echo message="grant codeBase "file:/${basedir}/build/test/classes" {" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
|
||||
<echo message="grant codeBase "file:/${basedir}/${file.reference.testng.jar}" {" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
|
||||
<echo message="grant codeBase "file:/${basedir}/test/script/basic/*" {" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
|
||||
<echo message="grant codeBase "file:/${basedir}/test/perf/*" {" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
|
||||
<replace file="${build.dir}/nashorn.policy"><replacetoken>\</replacetoken><replacevalue>/</replacevalue></replace> <!--hack for Windows - to make URLs with normal path separators -->
|
||||
<replace file="${build.dir}/nashorn.policy"><replacetoken>//</replacetoken><replacevalue>/</replacevalue></replace> <!--hack for Unix - to avoid leading // in URLs -->
|
||||
|
||||
</target>
|
||||
|
||||
<target name="check-external-tests">
|
||||
<available file="${test.external.dir}/prototype" property="test-sys-prop.external.prototype"/>
|
||||
<available file="${test.external.dir}/sunspider" property="test-sys-prop.external.sunspider"/>
|
||||
<available file="${test.external.dir}/underscore" property="test-sys-prop.external.underscore"/>
|
||||
<available file="${test.external.dir}/octane" property="test-sys-prop.external.octane"/>
|
||||
<available file="${test.external.dir}/yui" property="test-sys-prop.external.yui"/>
|
||||
<available file="${test.external.dir}/jquery" property="test-sys-prop.external.jquery"/>
|
||||
<available file="${test.external.dir}/test262" property="test-sys-prop.external.test262"/>
|
||||
</target>
|
||||
|
||||
<target name="check-testng" unless="testng.available">
|
||||
<echo message="WARNING: TestNG not available, will not run tests. Please copy testng.jar under test/lib directory."/>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
|
||||
<java classname="${nashorn.shell.tool}" fork="true" dir="${test.script.dir}/representations" output="${build.dir}/output1.log" error="${build.dir}/err.log">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="-Dnashorn.fields.dual=true"/>
|
||||
<arg value="NASHORN-592a.js"/>
|
||||
</java>
|
||||
<java classname="${nashorn.shell.tool}" fork="true" dir="${test.script.dir}/representations" output="${build.dir}/output2.log" error="${build.dir}/err.log">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<arg value="NASHORN-592a.js"/>
|
||||
</java>
|
||||
<condition property="representation-ok">
|
||||
<filesmatch file1="${build.dir}/output1.log" file2="${build.dir}/output2.log"/>
|
||||
</condition>
|
||||
<fail unless="representation-ok">Representation test failed - output differs!</fail>
|
||||
<fileset id="test.classes" dir="${build.test.classes.dir}">
|
||||
<include name="**/access/*Test.class"/>
|
||||
<include name="**/api/scripting/*Test.class"/>
|
||||
<include name="**/codegen/*Test.class"/>
|
||||
<include name="**/parser/*Test.class"/>
|
||||
<include name="**/runtime/*Test.class"/>
|
||||
<include name="**/framework/*Test.class"/>
|
||||
</fileset>
|
||||
|
||||
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
||||
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs} ${run.test.jvmsecurityargs}"/>
|
||||
<propertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</propertyset>
|
||||
<classpath>
|
||||
<pathelement path="${run.test.classpath}"/>
|
||||
</classpath>
|
||||
</testng>
|
||||
</target>
|
||||
|
||||
<target name="test-basicparallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file">
|
||||
<!-- use just build.test.classes.dir to avoid referring to TestNG -->
|
||||
<java classname="${parallel.test.runner}" dir="${basedir}" classpath="${build.test.classes.dir}" failonerror="true" fork="true">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs} ${run.test.jvmsecurityargs}"/>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper type="glob" from="test-sys-prop.*" to="*"/>
|
||||
</syspropertyset>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="test262" depends="jar, check-testng, check-external-tests, compile-test" if="testng.available">
|
||||
<fileset id="test.classes" dir="${build.test.classes.dir}">
|
||||
<include name="**/framework/*Test.class"/>
|
||||
</fileset>
|
||||
|
||||
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
||||
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<propertyset>
|
||||
<propertyref prefix="test262-test-sys-prop."/>
|
||||
<mapper from="test262-test-sys-prop.*" to="*" type="glob"/>
|
||||
</propertyset>
|
||||
<classpath>
|
||||
<pathelement path="${run.test.classpath}"/>
|
||||
</classpath>
|
||||
</testng>
|
||||
</target>
|
||||
|
||||
<target name="test262parallel" depends="test262-parallel"/>
|
||||
|
||||
<target name="test262-parallel" depends="jar, check-testng, check-external-tests, compile-test" if="testng.available">
|
||||
<!-- use just build.test.classes.dir to avoid referring to TestNG -->
|
||||
<java classname="${parallel.test.runner}" dir="${basedir}" classpath="${build.test.classes.dir}" fork="true">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test262-test-sys-prop."/>
|
||||
<mapper type="glob" from="test262-test-sys-prop.*" to="*"/>
|
||||
</syspropertyset>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="all" depends="test, docs"
|
||||
description="Build, test and generate docs for nashorn"/>
|
||||
|
||||
<target name="run" depends="jar"
|
||||
description="Run the shell with a sample script">
|
||||
<java classname="${nashorn.shell.tool}" fork="true" dir="samples">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<arg value="-dump-on-error"/>
|
||||
<arg value="test.js"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="debug" depends="jar"
|
||||
description="Debug the shell with a sample script">
|
||||
<java classname="${nashorn.shell.tool}" fork="true" dir="samples">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<arg value="--print-code"/>
|
||||
<arg value="--verify-code"/>
|
||||
<arg value="--print-symbols"/>
|
||||
<jvmarg value="-Dnashorn.codegen.debug=true"/>
|
||||
<arg value="test.js"/>
|
||||
</java>
|
||||
</target>
|
||||
</project>
|
||||
59
nashorn/make/nbproject/ide-file-targets.xml
Normal file
59
nashorn/make/nbproject/ide-file-targets.xml
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project basedir=".." name="nashorn-IDE">
|
||||
<property file="nbproject/nbjdk.properties"/>
|
||||
<property location="${netbeans.user}/build.properties" name="user.properties.file"/>
|
||||
<property file="${user.properties.file}"/>
|
||||
<import file="jdk.xml"/>
|
||||
<import file="${basedir}/build-init.xml"/>
|
||||
<!-- TODO: edit the following target according to your needs -->
|
||||
<!-- (more info: http://www.netbeans.org/kb/articles/freeform-config.html#runsingle) -->
|
||||
<target depends="-jdk-init, init" name="debug-selected-file-in-src">
|
||||
<fail unless="debug.class">Must set property 'debug.class'</fail>
|
||||
<ant antfile="build.xml" inheritall="false" target="jar"/>
|
||||
<nbjpdastart addressproperty="jpda.address" name="nashorn" transport="dt_socket">
|
||||
<classpath path="${run.test.classpath}"/>
|
||||
</nbjpdastart>
|
||||
<java classname="${debug.class}" fork="false">
|
||||
<classpath path="${run.test.classpath}"/>
|
||||
<jvmarg line="${boot.class.path}"/>
|
||||
<jvmarg value="-Xdebug"/>
|
||||
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<arg value="${debug.class}"/>
|
||||
</java>
|
||||
</target>
|
||||
<!-- TODO: edit the following target according to your needs -->
|
||||
<!-- (more info: http://www.netbeans.org/kb/articles/freeform-config.html#runsingle) -->
|
||||
<target depends="-jdk-init, init" name="run-selected-file-in-src">
|
||||
<fail unless="run.class">Must set property 'run.class'</fail>
|
||||
<ant antfile="build.xml" inheritall="false" target="jar"/>
|
||||
<java classname="${run.class}" failonerror="true" fork="false">
|
||||
<classpath path="${run.test.classpath}"/>
|
||||
<jvmarg line="${boot.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<arg value="${run.class}"/>
|
||||
</java>
|
||||
</target>
|
||||
</project>
|
||||
41
nashorn/make/nbproject/ide-targets.xml
Normal file
41
nashorn/make/nbproject/ide-targets.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<project basedir="../.." name="nashorn-IDE">
|
||||
<import file="../build.xml"/>
|
||||
<!-- TODO: edit the following target according to your needs -->
|
||||
<!-- (more info: http://www.netbeans.org/kb/articles/freeform-config.html#debugj2se) -->
|
||||
<target depends="jar" description="Run the shell with a sample script" name="debug-nb">
|
||||
<nbjpdastart addressproperty="jpda.address" name="nashorn" transport="dt_socket">
|
||||
<classpath path="${run.test.classpath}"/>
|
||||
</nbjpdastart>
|
||||
<java classname="jdk.nashorn.tools.Shell" classpath="${run.test.classpath}" dir="samples" fork="true">
|
||||
<jvmarg line="${ext.class.path}"/>
|
||||
<jvmarg line="${run.test.jvmargs}"/>
|
||||
<arg value="test.js"/>
|
||||
<jvmarg value="-Xdebug"/>
|
||||
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
|
||||
</java>
|
||||
</target>
|
||||
</project>
|
||||
179
nashorn/make/nbproject/jdk.xml
Normal file
179
nashorn/make/nbproject/jdk.xml
Normal file
@ -0,0 +1,179 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><project name="jdk" basedir=".">
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
|
||||
<description>
|
||||
Permits selection of a JDK to use when building and running project.
|
||||
See: http://www.netbeans.org/issues/show_bug.cgi?id=64160
|
||||
</description>
|
||||
|
||||
<target name="-jdk-pre-preinit">
|
||||
<condition property="nbjdk.active-or-nbjdk.home">
|
||||
<or>
|
||||
<and>
|
||||
<isset property="nbjdk.active"/>
|
||||
<not>
|
||||
<equals arg1="${nbjdk.active}" arg2="default_platform"/>
|
||||
</not>
|
||||
</and>
|
||||
<and>
|
||||
<isset property="nbjdk.home"/>
|
||||
<not>
|
||||
<isset property="nbjdk.home.defaulted"/>
|
||||
</not>
|
||||
</and>
|
||||
</or>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<target xmlns:common="http://java.netbeans.org/freeform/jdk.xml" name="-jdk-preinit" depends="-jdk-pre-preinit" if="nbjdk.active-or-nbjdk.home">
|
||||
<macrodef name="property" uri="http://java.netbeans.org/freeform/jdk.xml">
|
||||
<attribute name="name"/>
|
||||
<attribute name="value"/>
|
||||
<sequential>
|
||||
<property name="@{name}" value="${@{value}}"/>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<common:property name="nbjdk.home" value="platforms.${nbjdk.active}.home"/>
|
||||
<common:property name="nbjdk.javac.tmp" value="platforms.${nbjdk.active}.javac"/>
|
||||
<condition property=".exe" value=".exe">
|
||||
<os family="windows"/>
|
||||
</condition>
|
||||
<property name=".exe" value=""/>
|
||||
<condition property="nbjdk.javac" value="${nbjdk.home}/bin/javac${.exe}">
|
||||
<equals arg1="${nbjdk.javac.tmp}" arg2="$${platforms.${nbjdk.active}.javac}"/>
|
||||
</condition>
|
||||
<property name="nbjdk.javac" value="${nbjdk.javac.tmp}"/>
|
||||
<common:property name="nbjdk.java.tmp" value="platforms.${nbjdk.active}.java"/>
|
||||
<condition property="nbjdk.java" value="${nbjdk.home}/bin/java${.exe}">
|
||||
<equals arg1="${nbjdk.java.tmp}" arg2="$${platforms.${nbjdk.active}.java}"/>
|
||||
</condition>
|
||||
<property name="nbjdk.java" value="${nbjdk.java.tmp}"/>
|
||||
<common:property name="nbjdk.javadoc.tmp" value="platforms.${nbjdk.active}.javadoc"/>
|
||||
<condition property="nbjdk.javadoc" value="${nbjdk.home}/bin/javadoc${.exe}">
|
||||
<equals arg1="${nbjdk.javadoc.tmp}" arg2="$${platforms.${nbjdk.active}.javadoc}"/>
|
||||
</condition>
|
||||
<property name="nbjdk.javadoc" value="${nbjdk.javadoc.tmp}"/>
|
||||
<common:property name="nbjdk.bootclasspath.tmp" value="platforms.${nbjdk.active}.bootclasspath"/>
|
||||
<condition property="nbjdk.bootclasspath" value="${nbjdk.home}/jre/lib/rt.jar">
|
||||
<equals arg1="${nbjdk.bootclasspath.tmp}" arg2="$${platforms.${nbjdk.active}.bootclasspath}"/>
|
||||
</condition>
|
||||
<property name="nbjdk.bootclasspath" value="${nbjdk.bootclasspath.tmp}"/>
|
||||
<condition property="nbjdk.valid">
|
||||
<and>
|
||||
<available file="${nbjdk.home}" type="dir"/>
|
||||
<available file="${nbjdk.javac}" type="file"/>
|
||||
<available file="${nbjdk.java}" type="file"/>
|
||||
<available file="${nbjdk.javadoc}" type="file"/>
|
||||
|
||||
</and>
|
||||
</condition>
|
||||
<echo level="verbose">nbjdk.active=${nbjdk.active} nbjdk.home=${nbjdk.home} nbjdk.java=${nbjdk.java} nbjdk.javac=${nbjdk.javac} nbjdk.javadoc=${nbjdk.javadoc} nbjdk.bootclasspath=${nbjdk.bootclasspath} nbjdk.valid=${nbjdk.valid} have-jdk-1.4=${have-jdk-1.4} have-jdk-1.5=${have-jdk-1.5}</echo>
|
||||
</target>
|
||||
|
||||
<target name="-jdk-warn" depends="-jdk-preinit" if="nbjdk.active-or-nbjdk.home" unless="nbjdk.valid">
|
||||
<property name="jdkhome.presumed" location="${java.home}/.."/>
|
||||
<echo level="warning">Warning: nbjdk.active=${nbjdk.active} or nbjdk.home=${nbjdk.home} is an invalid Java platform; ignoring and using ${jdkhome.presumed}</echo>
|
||||
</target>
|
||||
|
||||
<target name="-jdk-presetdef-basic" depends="-jdk-preinit" if="nbjdk.valid" unless="nbjdk.presetdef.basic.done">
|
||||
|
||||
|
||||
<macrodef name="javac-presetdef">
|
||||
<attribute name="javacval"/>
|
||||
<sequential>
|
||||
<presetdef name="javac">
|
||||
<javac fork="yes" executable="@{javacval}"/>
|
||||
</presetdef>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<javac-presetdef javacval="${nbjdk.javac}"/>
|
||||
<macrodef name="java-presetdef">
|
||||
<attribute name="javaval"/>
|
||||
<sequential>
|
||||
<presetdef name="java">
|
||||
<java fork="yes" jvm="@{javaval}"/>
|
||||
</presetdef>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<java-presetdef javaval="${nbjdk.java}"/>
|
||||
<macrodef name="javadoc-presetdef">
|
||||
<attribute name="javadocval"/>
|
||||
<sequential>
|
||||
<presetdef name="javadoc">
|
||||
<javadoc executable="@{javadocval}"/>
|
||||
</presetdef>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<javadoc-presetdef javadocval="${nbjdk.javadoc}"/>
|
||||
<macrodef name="junit-presetdef">
|
||||
<attribute name="javaval"/>
|
||||
<sequential>
|
||||
<presetdef name="junit">
|
||||
<junit fork="yes" jvm="@{javaval}"/>
|
||||
</presetdef>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<junit-presetdef javaval="${nbjdk.java}"/>
|
||||
<property name="nbjdk.presetdef.basic.done" value="true"/>
|
||||
</target>
|
||||
|
||||
<target name="-jdk-presetdef-nbjpdastart" depends="-jdk-preinit" if="nbjdk.valid" unless="nbjdk.presetdef.nbjpdastart.done">
|
||||
<macrodef name="nbjpdastart-presetdef">
|
||||
<attribute name="bootcpval"/>
|
||||
<sequential>
|
||||
<presetdef name="nbjpdastart">
|
||||
<nbjpdastart>
|
||||
<bootclasspath>
|
||||
<path path="@{bootcpval}"/>
|
||||
</bootclasspath>
|
||||
</nbjpdastart>
|
||||
</presetdef>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<nbjpdastart-presetdef bootcpval="${nbjdk.bootclasspath}"/>
|
||||
<property name="nbjdk.presetdef.nbjpdastart.done" value="true"/>
|
||||
</target>
|
||||
|
||||
<target name="-jdk-default" unless="nbjdk.active-or-nbjdk.home">
|
||||
|
||||
<property name="java.home.parent" location="${java.home}/.."/>
|
||||
<condition property="nbjdk.home" value="${java.home.parent}">
|
||||
<available file="${java.home.parent}/lib/tools.jar" type="file"/>
|
||||
</condition>
|
||||
<condition property="nbjdk.home" value="${java.home}">
|
||||
<available file="${java.home}/lib/tools.jar" type="file"/>
|
||||
</condition>
|
||||
|
||||
<condition property="nbjdk.home" value="/Library/Java/Home">
|
||||
<available file="/Library/Java/Home" type="dir"/>
|
||||
</condition>
|
||||
|
||||
<property name="nbjdk.home" location="${java.home.parent}"/>
|
||||
<property name="nbjdk.home.defaulted" value="true"/>
|
||||
</target>
|
||||
|
||||
<target name="-jdk-init" depends="-jdk-preinit,-jdk-warn,-jdk-presetdef-basic,-jdk-default"/>
|
||||
|
||||
</project>
|
||||
24
nashorn/make/nbproject/nbjdk.properties
Normal file
24
nashorn/make/nbproject/nbjdk.properties
Normal file
@ -0,0 +1,24 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
nbjdk.active=JDK_1.8
|
||||
|
||||
48
nashorn/make/nbproject/nbjdk.xml
Normal file
48
nashorn/make/nbproject/nbjdk.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project basedir="..">
|
||||
<property file="../global.properties"/>
|
||||
<property file="nbproject/nbjdk.properties"/>
|
||||
<property location="${netbeans.user}/build.properties" name="user.properties.file"/>
|
||||
<property file="${user.properties.file}"/>
|
||||
<import file="jdk.xml"/>
|
||||
<target depends="-jdk-init" name="jar">
|
||||
<ant inheritall="false" target="jar"/>
|
||||
</target>
|
||||
<target depends="-jdk-init" name="clean">
|
||||
<ant inheritall="false" target="clean"/>
|
||||
</target>
|
||||
<target depends="-jdk-init" name="javadoc">
|
||||
<ant inheritall="false" target="javadoc"/>
|
||||
</target>
|
||||
<target depends="-jdk-init" name="test">
|
||||
<ant inheritall="false" target="test"/>
|
||||
</target>
|
||||
<target depends="-jdk-init" name="run">
|
||||
<ant inheritall="false" target="run"/>
|
||||
</target>
|
||||
<target depends="-jdk-init,-jdk-presetdef-nbjpdastart" name="debug-nb">
|
||||
<ant antfile="nbproject/ide-targets.xml" inheritall="false" target="debug-nb"/>
|
||||
</target>
|
||||
</project>
|
||||
177
nashorn/make/nbproject/project.xml
Normal file
177
nashorn/make/nbproject/project.xml
Normal file
@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.ant.freeform</type>
|
||||
<configuration>
|
||||
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
|
||||
<name>nashorn</name>
|
||||
</general-data>
|
||||
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/2">
|
||||
<!-- Do not use Project Properties customizer when editing this file manually. -->
|
||||
<name>nashorn</name>
|
||||
<properties/>
|
||||
<folders>
|
||||
<source-folder>
|
||||
<label>nashorn</label>
|
||||
<location>.</location>
|
||||
<encoding>UTF-8</encoding>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>../src</label>
|
||||
<location>../src</location>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>../test/src</label>
|
||||
<location>../test/src</location>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>../buildtools/nasgen/src</label>
|
||||
<location>../buildtools/nasgen/src</location>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>../test/src</label>
|
||||
<type>java</type>
|
||||
<location>../test/src</location>
|
||||
<encoding>UTF-8</encoding>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>../src</label>
|
||||
<type>java</type>
|
||||
<location>../src</location>
|
||||
<encoding>UTF-8</encoding>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>../buildtools/nasgen/src</label>
|
||||
<type>java</type>
|
||||
<location>../buildtools/nasgen/src</location>
|
||||
<encoding>UTF-8</encoding>
|
||||
</source-folder>
|
||||
</folders>
|
||||
<ide-actions>
|
||||
<action name="build">
|
||||
<script>nbproject/nbjdk.xml</script>
|
||||
<target>jar</target>
|
||||
</action>
|
||||
<action name="clean">
|
||||
<script>nbproject/nbjdk.xml</script>
|
||||
<target>clean</target>
|
||||
</action>
|
||||
<action name="javadoc">
|
||||
<script>nbproject/nbjdk.xml</script>
|
||||
<target>javadoc</target>
|
||||
</action>
|
||||
<action name="test">
|
||||
<script>nbproject/nbjdk.xml</script>
|
||||
<target>test</target>
|
||||
</action>
|
||||
<action name="rebuild">
|
||||
<script>nbproject/nbjdk.xml</script>
|
||||
<target>clean</target>
|
||||
<target>jar</target>
|
||||
</action>
|
||||
<action name="run">
|
||||
<script>nbproject/nbjdk.xml</script>
|
||||
<target>run</target>
|
||||
</action>
|
||||
<action name="debug">
|
||||
<script>nbproject/nbjdk.xml</script>
|
||||
<target>debug-nb</target>
|
||||
</action>
|
||||
<action name="debug.single">
|
||||
<script>nbproject/ide-file-targets.xml</script>
|
||||
<target>debug-selected-file-in-src</target>
|
||||
<context>
|
||||
<property>debug.class</property>
|
||||
<folder>test/src</folder>
|
||||
<pattern>\.java$</pattern>
|
||||
<format>java-name</format>
|
||||
<arity>
|
||||
<one-file-only/>
|
||||
</arity>
|
||||
</context>
|
||||
</action>
|
||||
<action name="run.single">
|
||||
<script>nbproject/ide-file-targets.xml</script>
|
||||
<target>run-selected-file-in-src</target>
|
||||
<context>
|
||||
<property>run.class</property>
|
||||
<folder>test/src</folder>
|
||||
<pattern>\.java$</pattern>
|
||||
<format>java-name</format>
|
||||
<arity>
|
||||
<one-file-only/>
|
||||
</arity>
|
||||
</context>
|
||||
</action>
|
||||
</ide-actions>
|
||||
<view>
|
||||
<items>
|
||||
<source-folder style="packages">
|
||||
<label>../test/src</label>
|
||||
<location>../test/src</location>
|
||||
</source-folder>
|
||||
<source-folder style="packages">
|
||||
<label>../src</label>
|
||||
<location>../src</location>
|
||||
</source-folder>
|
||||
<source-folder style="packages">
|
||||
<label>../buildtools/nasgen/src</label>
|
||||
<location>../buildtools/nasgen/src</location>
|
||||
</source-folder>
|
||||
<source-file>
|
||||
<location>build.xml</location>
|
||||
</source-file>
|
||||
</items>
|
||||
<context-menu>
|
||||
<ide-action name="build"/>
|
||||
<ide-action name="rebuild"/>
|
||||
<ide-action name="clean"/>
|
||||
<ide-action name="javadoc"/>
|
||||
<ide-action name="run"/>
|
||||
<ide-action name="test"/>
|
||||
<ide-action name="debug"/>
|
||||
</context-menu>
|
||||
</view>
|
||||
<subprojects/>
|
||||
</general-data>
|
||||
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/3">
|
||||
<compilation-unit>
|
||||
<package-root>../test/src</package-root>
|
||||
<unit-tests/>
|
||||
<classpath mode="compile">../test/lib/testng.jar:../build/classes:../src</classpath>
|
||||
<source-level>1.7</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>../src</package-root>
|
||||
<classpath mode="compile">../build/dynalink/dynalink.jar</classpath>
|
||||
<source-level>1.7</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>../buildtools/nasgen/src</package-root>
|
||||
<classpath mode="compile">../build/classes:../src</classpath>
|
||||
<source-level>1.7</source-level>
|
||||
</compilation-unit>
|
||||
</java-data>
|
||||
</configuration>
|
||||
</project>
|
||||
223
nashorn/make/project.properties
Normal file
223
nashorn/make/project.properties
Normal file
@ -0,0 +1,223 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
application.title=nashorn
|
||||
|
||||
# source and target levels
|
||||
build.compiler=modern
|
||||
javac.source=1.7
|
||||
javac.target=1.7
|
||||
|
||||
# nashorn version information
|
||||
nashorn.version=0.1
|
||||
nashorn.fullversion=0.1
|
||||
nashorn.product.name=Oracle Nashorn
|
||||
|
||||
# This directory is removed when the project is cleaned:
|
||||
build.dir=build
|
||||
build.classes.dir=${build.dir}/classes
|
||||
build.zip=${build.dir}/nashorn.zip
|
||||
build.gzip=${build.dir}/nashorn.tar.gz
|
||||
|
||||
# nashorn Shell tool
|
||||
nashorn.shell.tool=jdk.nashorn.tools.Shell
|
||||
|
||||
# nasgen tool
|
||||
nasgen.tool=jdk.nashorn.internal.tools.nasgen.Main
|
||||
|
||||
# parallel test runner tool
|
||||
parallel.test.runner=jdk.nashorn.internal.test.framework.ParallelTestRunner
|
||||
|
||||
# test classes directory
|
||||
build.test.classes.dir=${build.dir}/test/classes
|
||||
# test results directory
|
||||
build.test.results.dir=${build.dir}/test/reports
|
||||
|
||||
# This directory is removed when the project is cleaned:
|
||||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/nashorn.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
|
||||
# directory where asm project lives
|
||||
asm.dir=../asm
|
||||
asm.src.dir=${asm.dir}/src
|
||||
|
||||
# jars refererred
|
||||
file.reference.testng.jar=test/lib/testng.jar
|
||||
|
||||
# Set testng verbose level
|
||||
# From TestNG docs: "the verbosity level (0 to 10 where 10 is most detailed)
|
||||
# Actually, this is a lie: you can specify -1 and this will put TestNG in
|
||||
# debug mode (no longer slicing off stack traces and all)."
|
||||
|
||||
testng.verbose=2
|
||||
|
||||
# TestNG listeners - we want to replace TestNG's own JUnit
|
||||
# reporter, but want everything else provided by default
|
||||
# Unfortunately, we've to clone the other default reporters here.
|
||||
|
||||
testng.listeners=\
|
||||
org.testng.reporters.SuiteHTMLReporter, \
|
||||
org.testng.reporters.jq.Main, \
|
||||
org.testng.reporters.FailedReporter, \
|
||||
org.testng.reporters.XMLReporter \
|
||||
org.testng.reporters.EmailableReporter, \
|
||||
jdk.nashorn.internal.test.framework.JSJUnitReportReporter
|
||||
|
||||
# Define the version of Dynalink that is used. Version types are either
|
||||
# 'snapshot' or 'release'. When it is 'snapshot', the version must have
|
||||
# "-SNAPSHOT" suffix and the jar version will have a timestamp in it. When
|
||||
# it's 'release', the version has no suffix, and the jar version is
|
||||
# identical to version - fun with Maven central.
|
||||
dynalink.version=0.5-SNAPSHOT
|
||||
dynalink.version.type=snapshot
|
||||
dynalink.jar.version=0.5-20121218.140128-11
|
||||
dynalink.dir.name=dynalink
|
||||
dynalink.dir=build/${dynalink.dir.name}
|
||||
dynalink.jar=${dynalink.dir}/dynalink.jar
|
||||
|
||||
javac.debug=true
|
||||
javac.encoding=ascii
|
||||
javac.classpath=\
|
||||
${build.classes.dir}:\
|
||||
${dynalink.jar}
|
||||
javac.test.classpath=\
|
||||
${build.classes.dir}:\
|
||||
${build.test.classes.dir}:\
|
||||
${file.reference.testng.jar}
|
||||
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
|
||||
run.classpath=\
|
||||
${build.classes.dir}
|
||||
|
||||
# test scripts to run
|
||||
test.dir=test
|
||||
test.script.dir=test/script
|
||||
test.basic.dir=test/script/basic
|
||||
test.error.dir=test/script/error
|
||||
test.sandbox.dir=test/script/sandbox
|
||||
test.external.dir=test/script/external
|
||||
test262.dir=${test.external.dir}/test262
|
||||
test262.suite.dir=${test262.dir}/test/suite
|
||||
|
||||
test-sys-prop.test.dir=${test.dir}
|
||||
test-sys-prop.test.js.roots=${test.basic.dir} ${test.error.dir} ${test.sandbox.dir}
|
||||
test-sys-prop.test262.suite.dir=${test262.suite.dir}
|
||||
test-sys-prop.es5conform.testcases.dir=${test.external.dir}/ES5Conform/TestCases
|
||||
test-sys-prop.test.basic.dir=${test.basic.dir}
|
||||
|
||||
# framework root for our script tests
|
||||
test-sys-prop.test.js.framework=${test.script.dir}/assert.js
|
||||
|
||||
# Control the verbosity of ParserTest
|
||||
test-sys-prop.parsertest.verbose=false
|
||||
|
||||
# turn on/off scripting mode for parser tests
|
||||
test-sys-prop.parsertest.scripting=true
|
||||
|
||||
# turn on/off test262 scripts for parser tests
|
||||
test-sys-prop.parsertest.test262=false
|
||||
|
||||
# Control the verbosity of the CompilerTest
|
||||
test-sys-prop.compilertest.verbose=false
|
||||
|
||||
# turn on/off scripting mode for compiler tests
|
||||
test-sys-prop.compilertest.scripting=true
|
||||
|
||||
# turn on/off test262 scripts for compiler tests
|
||||
test-sys-prop.compilertest.test262=false
|
||||
|
||||
# test directory to be excluded.
|
||||
test-sys-prop.test.js.exclude.dir=${test.script.dir}/currently-failing ${test.external.dir}
|
||||
|
||||
# run everything that's js in here, without checking file headers for test annotations
|
||||
test-sys-prop.test.js.unchecked.dir=${test262.dir}
|
||||
|
||||
# test root for octane
|
||||
octane-test-sys-prop.test.js.roots=${test.external.dir}/octane/benchmarks
|
||||
|
||||
# framework root for octane
|
||||
octane-test-sys-prop.test.js.framework=${test.basic.dir}/run-octane.js
|
||||
|
||||
# list of tests to be excluded
|
||||
octane-test-sys-prop.test.js.exclude.list=base.js
|
||||
|
||||
# test root for sunspider
|
||||
sunspider-test-sys-prop.test.js.roots=${test.external.dir}/sunspider/
|
||||
|
||||
# framework root for sunspider
|
||||
sunspider-test-sys-prop.test.js.framework=${test.basic.dir}/runsunspider.js
|
||||
|
||||
# list of tests to be excluded
|
||||
sunspider-test-sys-prop.test.js.exclude.list=
|
||||
|
||||
# execute our script tests in shared nashorn context or not?
|
||||
test-sys-prop.test.js.shared.context=false
|
||||
|
||||
# execute test262 tests in shared nashorn context or not?
|
||||
test262-test-sys-prop.test.js.shared.context=true
|
||||
|
||||
# test262 test root
|
||||
test262-test-sys-prop.test.js.roots=${test262.suite.dir}
|
||||
# test262 enable/disable strict mode tests
|
||||
test262-test-sys-prop.test.js.enable.strict.mode=true
|
||||
|
||||
# file containing test262 tests to be excluded
|
||||
# test262-test-sys-prop.test.js.excludes.file=${test262.dir}/test/config/excludelist.xml
|
||||
|
||||
# list of test262 test dirs to be excluded
|
||||
test262-test-sys-prop.test.js.exclude.dir=\
|
||||
${test262.suite.dir}/intl402/
|
||||
|
||||
# test262 test frameworks
|
||||
test262-test-sys-prop.test.js.framework=\
|
||||
-timezone=PST \
|
||||
${test.script.dir}/test262.js \
|
||||
${test262.dir}/test/harness/framework.js \
|
||||
${test262.dir}/test/harness/sta.js
|
||||
|
||||
run.test.classpath=\
|
||||
${file.reference.testng.jar}:\
|
||||
${build.test.classes.dir}
|
||||
src.dir=src
|
||||
test.src.dir=test/src
|
||||
|
||||
# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods
|
||||
# add '-Dtest.js.outofprocess' to run each test in a new sub-process
|
||||
run.test.jvmargs=-server -Xmx3G -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
|
||||
#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
|
||||
run.test.jvmargs.octane=-Xms2G -Xmx2G ${run.test.jvmargs}
|
||||
|
||||
run.test.jvmsecurityargs=-Xverify:all -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy
|
||||
|
||||
# path of rhino.jar for benchmarks
|
||||
rhino.jar=
|
||||
|
||||
v8.shell=d8
|
||||
|
||||
#path to rhino jar file
|
||||
octaneperf-sys-prop.rhino.jar=${rhino.jar}
|
||||
|
||||
#timeout for performance tests in minutes
|
||||
octaneperf-sys-prop.timeout.value=10
|
||||
39
nashorn/samples/counters.js
Normal file
39
nashorn/samples/counters.js
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. 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 Oracle 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file can be run along with any script you want to run
|
||||
* to print aggregate stat counters from nashorn.
|
||||
*
|
||||
* Usage: jjs <your-file.js> counters.js
|
||||
*/
|
||||
|
||||
Debug.dumpCounters();
|
||||
49
nashorn/samples/letter.js
Normal file
49
nashorn/samples/letter.js
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. 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 Oracle 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Demonstrates "heredoc" feature with "scripting" mode.
|
||||
*
|
||||
* Usage: jjs -scripting letter.js -- <sender> <recipient>
|
||||
*/
|
||||
|
||||
# This is shell-style line comment
|
||||
var obj = { sender: $ARG[0], recipient: $ARG[1] };
|
||||
|
||||
// JavaScript style line comment is ok too.
|
||||
print(<<EOF);
|
||||
Dear ${obj.recipient},
|
||||
|
||||
I wish you all the best.
|
||||
|
||||
Regards,
|
||||
${obj.sender}
|
||||
EOF
|
||||
43
nashorn/samples/parser.js
Normal file
43
nashorn/samples/parser.js
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. 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 Oracle 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Simple sample demonstrating parser API.
|
||||
*/
|
||||
|
||||
load("nashorn:parser.js");
|
||||
try {
|
||||
var json = parse("print('hello')");
|
||||
print(JSON.stringify(json));
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
78
nashorn/samples/shell.js
Normal file
78
nashorn/samples/shell.js
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. 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 Oracle 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a simple shell tool in JavaScript.
|
||||
*
|
||||
* Runs any operating system command using Java "exec". When "eval" command is
|
||||
* used, evaluates argument(s) as JavaScript code.
|
||||
*/
|
||||
|
||||
var imports = new JavaImporter(java.io, java.lang, java.util);
|
||||
|
||||
function prompt() {
|
||||
java.lang.System.out.print(">");
|
||||
}
|
||||
|
||||
with (imports) {
|
||||
var reader = new BufferedReader(new InputStreamReader(System["in"]));
|
||||
var line = null;
|
||||
prompt();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line != "") {
|
||||
var args = line.split(" ");
|
||||
try {
|
||||
if (args[0] == "eval") {
|
||||
var code = line.substring("eval".length);
|
||||
var res = eval(code);
|
||||
if (res != undefined) {
|
||||
print(res);
|
||||
}
|
||||
} else {
|
||||
var argList = new ArrayList();
|
||||
for (i in args) { argList.add(args[i]); }
|
||||
var procBuilder = new ProcessBuilder(argList);
|
||||
procBuilder.redirectErrorStream();
|
||||
var proc = procBuilder.start();
|
||||
var out = new BufferedReader(new InputStreamReader(proc.getInputStream()));
|
||||
var line = null;
|
||||
while ((line = out.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
}
|
||||
proc.waitFor();
|
||||
}
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
prompt();
|
||||
}
|
||||
}
|
||||
32
nashorn/samples/test.js
Normal file
32
nashorn/samples/test.js
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. 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 Oracle 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.
|
||||
*/
|
||||
|
||||
print("Hello World");
|
||||
55
nashorn/samples/uniq.js
Normal file
55
nashorn/samples/uniq.js
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. 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 Oracle 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prints unique lines from a given file.
|
||||
*/
|
||||
|
||||
if (arguments.length != 1) {
|
||||
print("Usage: jjs uniq.js -- <file>");
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
|
||||
var imports = new JavaImporter(java.io);
|
||||
|
||||
var uniqueLines = {};
|
||||
with (imports) {
|
||||
var reader = new BufferedReader(new FileReader(arguments[0]));
|
||||
while ((line = reader.readLine()) != null) {
|
||||
// using a JS object as a map...
|
||||
uniqueLines[line] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// now print the collected lines
|
||||
for (i in uniqueLines) {
|
||||
print(i);
|
||||
}
|
||||
5
nashorn/src/META-INF/MANIFEST.MF
Normal file
5
nashorn/src/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,5 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: jdk.nashorn.tools.Shell
|
||||
|
||||
Name: jdk/nashorn/
|
||||
Implementation-Vendor: Oracle Corporation
|
||||
@ -0,0 +1,25 @@
|
||||
#
|
||||
# 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. 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.nashorn.api.scripting.NashornScriptEngineFactory
|
||||
121
nashorn/src/jdk/nashorn/api/scripting/NashornException.java
Normal file
121
nashorn/src/jdk/nashorn/api/scripting/NashornException.java
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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. 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.nashorn.api.scripting;
|
||||
|
||||
/**
|
||||
* This is base exception for all Nashorn exceptions. These originate from user's
|
||||
* ECMAScript code. Example: script parse errors, exceptions thrown from scripts.
|
||||
* Note that ScriptEngine methods like "eval", "invokeMethod", "invokeFunction"
|
||||
* will wrap this as ScriptException and throw it. But, there are cases where user
|
||||
* may need to access this exception (or implementation defined subtype of this).
|
||||
* For example, if java interface is implemented by a script object or Java access
|
||||
* to script object properties via java.util.Map interface. In these cases, user
|
||||
* code will get an instance of this or implementation defined subclass.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NashornException extends RuntimeException {
|
||||
// script file name
|
||||
private String fileName;
|
||||
// script line number
|
||||
private int line;
|
||||
// script column number
|
||||
private int column;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param msg exception message
|
||||
*/
|
||||
protected NashornException(final String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param msg exception message
|
||||
* @param cause exception cause
|
||||
*/
|
||||
protected NashornException(final String msg, final Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param cause exception cause
|
||||
*/
|
||||
protected NashornException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source file name for this {@code NashornException}
|
||||
* @return the file name
|
||||
*/
|
||||
public final String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source file name for this {@code NashornException}
|
||||
* @param fileName file name
|
||||
*/
|
||||
protected final void setFileName(final String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line number for this {@code NashornException}
|
||||
* @return the line number
|
||||
*/
|
||||
public final int getLineNumber() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the line number for this {@code NashornException}
|
||||
* @param line line number
|
||||
*/
|
||||
protected final void setLineNumber(final int line) {
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the column for this {@code NashornException}
|
||||
* @return the column
|
||||
*/
|
||||
public final int getColumnNumber() {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column number for this {@code NashornException}
|
||||
* @param column the column
|
||||
*/
|
||||
public final void setColumnNumber(final int column) {
|
||||
this.column = column;
|
||||
}
|
||||
}
|
||||
521
nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
Normal file
521
nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
Normal file
@ -0,0 +1,521 @@
|
||||
/*
|
||||
* 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. 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.nashorn.api.scripting;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import javax.script.AbstractScriptEngine;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ErrorManager;
|
||||
import jdk.nashorn.internal.runtime.GlobalObject;
|
||||
import jdk.nashorn.internal.runtime.Property;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
|
||||
import jdk.nashorn.internal.runtime.options.Options;
|
||||
|
||||
/**
|
||||
* JSR-223 compliant script engine for Nashorn. Instances are not created directly, but rather returned through
|
||||
* {@link NashornScriptEngineFactory#getScriptEngine()}. Note that this engine implements the {@link Compilable} and
|
||||
* {@link Invocable} interfaces, allowing for efficient precompilation and repeated execution of scripts.
|
||||
* @see NashornScriptEngineFactory
|
||||
*/
|
||||
|
||||
public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable {
|
||||
|
||||
private final ScriptEngineFactory factory;
|
||||
private final Context nashornContext;
|
||||
private final ScriptObject global;
|
||||
|
||||
// default options passed to Nashorn Options object
|
||||
private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-af", "-doe" };
|
||||
|
||||
NashornScriptEngine(final NashornScriptEngineFactory factory) {
|
||||
this(factory, DEFAULT_OPTIONS);
|
||||
}
|
||||
|
||||
@SuppressWarnings("LeakingThisInConstructor")
|
||||
NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args) {
|
||||
this.factory = factory;
|
||||
final Options options = new Options("nashorn");
|
||||
options.process(args);
|
||||
|
||||
// throw ParseException on first error from script
|
||||
final ErrorManager errors = new Context.ThrowErrorManager();
|
||||
// create new Nashorn Context and get global object
|
||||
this.nashornContext = AccessController.doPrivileged(new PrivilegedAction<Context>() {
|
||||
@Override
|
||||
public Context run() {
|
||||
try {
|
||||
return new Context(options, errors);
|
||||
} catch (final RuntimeException e) {
|
||||
if (Context.DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// create new global object
|
||||
this.global = nashornContext.createGlobal();
|
||||
|
||||
// current ScriptContext exposed as "context"
|
||||
global.addOwnProperty("context", Property.NOT_ENUMERABLE, context);
|
||||
// current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as
|
||||
// NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property
|
||||
// in the Global of a Context we just created - both the Context and the Global were just created and can not be
|
||||
// seen from another thread outside of this constructor.
|
||||
global.addOwnProperty("engine", Property.NOT_ENUMERABLE, this);
|
||||
// global script arguments
|
||||
global.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED);
|
||||
|
||||
// evaluate engine initial script
|
||||
try {
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
@Override
|
||||
public Void run() throws ScriptException {
|
||||
evalEngineScript();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (final PrivilegedActionException e) {
|
||||
if (Context.DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final Reader reader, final ScriptContext ctxt) throws ScriptException {
|
||||
try {
|
||||
return evalImpl(Source.readFully(reader), ctxt);
|
||||
} catch (final IOException e) {
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final String script, final ScriptContext ctxt) throws ScriptException {
|
||||
return evalImpl(script.toCharArray(), ctxt);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: This is not exactly right. Script execution should actually
|
||||
* put the variables in ENGINE_SCOPE bindings. But, it is difficult
|
||||
* (not possible?) with the way ScriptObject is implemented. So, for now
|
||||
* giving access to script variables by accessing it from "globals". This
|
||||
* way at least engine.get("foo") will work whenever "foo" is a global var
|
||||
* defined by eval'ed scripts.
|
||||
*/
|
||||
@Override
|
||||
public Object get(final String key) {
|
||||
Object value = super.get(key);
|
||||
if (value == null) {
|
||||
value = ScriptObjectMirror.wrap(global.get(key), global);
|
||||
}
|
||||
return (value == UNDEFINED) ? null : value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngineFactory getFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bindings createBindings() {
|
||||
return new SimpleBindings();
|
||||
}
|
||||
|
||||
// Compilable methods
|
||||
|
||||
@Override
|
||||
public CompiledScript compile(final Reader reader) throws ScriptException {
|
||||
try {
|
||||
return asCompiledScript(compileImpl(Source.readFully(reader), context));
|
||||
} catch (final IOException e) {
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompiledScript compile(final String str) throws ScriptException {
|
||||
return asCompiledScript(compileImpl(str.toCharArray(), context));
|
||||
}
|
||||
|
||||
// Invocable methods
|
||||
|
||||
@Override
|
||||
public Object invokeFunction(final String name, final Object... args)
|
||||
throws ScriptException, NoSuchMethodException {
|
||||
return invokeImpl(null, name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeMethod(final Object self, final String name, final Object... args)
|
||||
throws ScriptException, NoSuchMethodException {
|
||||
if (self == null) {
|
||||
throw new IllegalArgumentException("script object can not be null");
|
||||
}
|
||||
return invokeImpl(self, name, args);
|
||||
}
|
||||
|
||||
private <T> T getInterfaceInner(final Object self, final Class<T> clazz) {
|
||||
final Object realSelf;
|
||||
if(self == null) {
|
||||
realSelf = global;
|
||||
} else if (!(self instanceof ScriptObject)) {
|
||||
realSelf = ScriptObjectMirror.unwrap(self, global);
|
||||
} else {
|
||||
realSelf = self;
|
||||
}
|
||||
try {
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
try {
|
||||
if(oldGlobal != global) {
|
||||
setNashornGlobal(global);
|
||||
}
|
||||
return clazz.cast(JavaAdapterFactory.getConstructor(realSelf.getClass(), clazz).invoke(realSelf));
|
||||
} finally {
|
||||
if(oldGlobal != global) {
|
||||
setNashornGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
} catch(final RuntimeException|Error e) {
|
||||
throw e;
|
||||
} catch(final Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(final Class<T> clazz) {
|
||||
return getInterfaceInner(null, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(final Object self, final Class<T> clazz) {
|
||||
if (self == null) {
|
||||
throw new IllegalArgumentException("script object can not be null");
|
||||
}
|
||||
return getInterfaceInner(self, clazz);
|
||||
}
|
||||
|
||||
// These are called from the "engine.js" script
|
||||
|
||||
/**
|
||||
* This hook is used to search js global variables exposed from Java code.
|
||||
*
|
||||
* @param self 'this' passed from the script
|
||||
* @param ctxt current ScriptContext in which name is searched
|
||||
* @param name name of the variable searched
|
||||
* @return the value of the named variable
|
||||
*/
|
||||
public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) {
|
||||
final int scope = ctxt.getAttributesScope(name);
|
||||
if (scope != -1) {
|
||||
return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), global);
|
||||
}
|
||||
|
||||
if (self == UNDEFINED) {
|
||||
// scope access and so throw ReferenceError
|
||||
referenceError(global, "not.defined", name);
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* This hook is used to call js global functions exposed from Java code.
|
||||
*
|
||||
* @param self 'this' passed from the script
|
||||
* @param ctxt current ScriptContext in which method is searched
|
||||
* @param name name of the method
|
||||
* @param args arguments to be passed to the method
|
||||
* @return return value of the called method
|
||||
*/
|
||||
public Object __noSuchMethod__(final Object self, final ScriptContext ctxt, final String name, final Object args) {
|
||||
final int scope = ctxt.getAttributesScope(name);
|
||||
Object value;
|
||||
|
||||
if (scope != -1) {
|
||||
value = ctxt.getAttribute(name, scope);
|
||||
} else {
|
||||
if (self == UNDEFINED) {
|
||||
referenceError(global, "not.defined", name);
|
||||
} else {
|
||||
typeError(global, "no.such.function", name, ScriptRuntime.safeToString(global));
|
||||
}
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
value = ScriptObjectMirror.unwrap(value, global);
|
||||
|
||||
if (value instanceof Method) {
|
||||
final Method method = (Method) value;
|
||||
final int mods = method.getModifiers();
|
||||
if (Modifier.isStatic(mods) && Modifier.isPublic(mods)) {
|
||||
value = MH.find((Method)value);
|
||||
}
|
||||
}
|
||||
|
||||
if (value instanceof MethodHandle) {
|
||||
value = ((GlobalObject)global).newScriptFunction(name, (MethodHandle)value, null, false);
|
||||
}
|
||||
|
||||
if (!(value instanceof ScriptFunction)) {
|
||||
typeError(global, "not.a.function", name);
|
||||
}
|
||||
|
||||
if (value instanceof ScriptFunction) {
|
||||
return ScriptObjectMirror.unwrap(ScriptRuntime.apply((ScriptFunction)value, global, args), global);
|
||||
}
|
||||
|
||||
typeError(global, "not.a.function", ScriptRuntime.safeToString(name));
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
private void evalEngineScript() throws ScriptException {
|
||||
final URL url = NashornScriptEngine.class.getResource("resources/engine.js");
|
||||
try {
|
||||
final InputStream is = url.openStream();
|
||||
put(ScriptEngine.FILENAME, url);
|
||||
try (final InputStreamReader isr = new InputStreamReader(is)) {
|
||||
eval(isr);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new ScriptException(e);
|
||||
} finally {
|
||||
put(ScriptEngine.FILENAME, null);
|
||||
}
|
||||
}
|
||||
|
||||
// scripts should see "context" and "engine" as variables
|
||||
private void setContextVariables(final ScriptContext ctxt) {
|
||||
ctxt.setAttribute("context", ctxt, ScriptContext.ENGINE_SCOPE);
|
||||
// current ScriptContext exposed as "context"
|
||||
global.set("context", ctxt, false);
|
||||
Object args = ctxt.getAttribute("arguments");
|
||||
// if no arguments passed, make it empty array
|
||||
if (args == null) {
|
||||
args = ScriptRuntime.EMPTY_ARRAY;
|
||||
}
|
||||
args = ((GlobalObject)global).wrapAsObject(args);
|
||||
global.set("arguments", args, false);
|
||||
}
|
||||
|
||||
private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
final boolean globalChanged = (oldGlobal != global);
|
||||
|
||||
Object self = selfObject;
|
||||
|
||||
try {
|
||||
if (globalChanged) {
|
||||
setNashornGlobal(global);
|
||||
}
|
||||
|
||||
ScriptObject sobj;
|
||||
Object value;
|
||||
|
||||
self = ScriptObjectMirror.unwrap(self, global);
|
||||
|
||||
// FIXME: should convert when self is not ScriptObject
|
||||
if (self instanceof ScriptObject) {
|
||||
sobj = (ScriptObject)self;
|
||||
value = sobj.get(name);
|
||||
} else if (self == null) {
|
||||
self = global;
|
||||
sobj = global;
|
||||
value = sobj.get(name);
|
||||
} else {
|
||||
// Find the java method and make a ScriptFunction of it.
|
||||
final Method[] methods = self.getClass().getMethods();
|
||||
Method target = null;
|
||||
|
||||
for (final Method mth : methods) {
|
||||
// choose the right overload by number of arguments -- don't
|
||||
// care overload resolution for now..
|
||||
if (mth.getName().equals(name) &&
|
||||
mth.getParameterTypes().length == args.length) {
|
||||
target = mth;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target == null) {
|
||||
throw new NoSuchMethodException(name);
|
||||
}
|
||||
final GlobalObject gobj = (GlobalObject) global;
|
||||
value = gobj.newScriptFunction(name, MH.find(target), null, false);
|
||||
}
|
||||
|
||||
if (value instanceof ScriptFunction) {
|
||||
final Object res;
|
||||
try {
|
||||
res = ScriptRuntime.apply((ScriptFunction)value, self, ScriptObjectMirror.unwrapArray(args, global));
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e);
|
||||
throw new AssertionError("should not reach here");
|
||||
}
|
||||
return ScriptObjectMirror.wrap(res, global);
|
||||
}
|
||||
|
||||
throw new NoSuchMethodException(name);
|
||||
} finally {
|
||||
if (globalChanged) {
|
||||
setNashornGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object evalImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException {
|
||||
return evalImpl(compileImpl(buf, ctxt), ctxt);
|
||||
}
|
||||
|
||||
private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt) throws ScriptException {
|
||||
if (script == null) {
|
||||
return null;
|
||||
}
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
final boolean globalChanged = (oldGlobal != global);
|
||||
try {
|
||||
if (globalChanged) {
|
||||
setNashornGlobal(global);
|
||||
}
|
||||
|
||||
setContextVariables(ctxt);
|
||||
Object res = ScriptRuntime.apply(script, global);
|
||||
res = ScriptObjectMirror.wrap(res, global);
|
||||
return (res == UNDEFINED) ? null : res;
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e);
|
||||
throw new AssertionError("should not reach here");
|
||||
} finally {
|
||||
if (globalChanged) {
|
||||
setNashornGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void throwAsScriptException(final Exception e) throws ScriptException {
|
||||
if (e instanceof ScriptException) {
|
||||
throw (ScriptException)e;
|
||||
} else if (e instanceof NashornException) {
|
||||
final NashornException ne = (NashornException)e;
|
||||
final ScriptException se = new ScriptException(
|
||||
ne.getMessage(), ne.getFileName(),
|
||||
ne.getLineNumber(), ne.getColumnNumber());
|
||||
se.initCause(e);
|
||||
throw se;
|
||||
} else if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException)e;
|
||||
} else {
|
||||
// wrap any other exception as ScriptException
|
||||
throw new ScriptException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private CompiledScript asCompiledScript(final ScriptFunction script) {
|
||||
return new CompiledScript() {
|
||||
@Override
|
||||
public Object eval(final ScriptContext ctxt) throws ScriptException {
|
||||
return evalImpl(script, ctxt);
|
||||
}
|
||||
@Override
|
||||
public ScriptEngine getEngine() {
|
||||
return NashornScriptEngine.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ScriptFunction compileImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException {
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
final boolean globalChanged = (oldGlobal != global);
|
||||
try {
|
||||
final Object val = ctxt.getAttribute(ScriptEngine.FILENAME);
|
||||
final String fileName = (val != null) ? val.toString() : "<eval>";
|
||||
|
||||
// !!HACK!! do not evaluate "init.js" from jrunscript tool!!
|
||||
if ("<system-init>".equals(fileName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Source source = new Source(fileName, buf);
|
||||
if (globalChanged) {
|
||||
setNashornGlobal(global);
|
||||
}
|
||||
|
||||
setContextVariables(ctxt);
|
||||
return nashornContext.compileScript(source, global, nashornContext._strict);
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e);
|
||||
throw new AssertionError("should not reach here");
|
||||
} finally {
|
||||
if (globalChanged) {
|
||||
setNashornGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't make this public!!
|
||||
static void setNashornGlobal(final ScriptObject global) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
Context.setGlobal(global);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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. 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.nashorn.api.scripting;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import jdk.nashorn.internal.runtime.Version;
|
||||
|
||||
/**
|
||||
* JSR-223 compliant script engine factory for Nashorn. The engine answers for:
|
||||
* <ul>
|
||||
* <li>names {@code "nashorn"}, {@code "Nashorn"}, {@code "js"}, {@code "JS"}, {@code "JavaScript"},
|
||||
* {@code "javascript"}, {@code "ECMAScript"}, and {@code "ecmascript"};</li>
|
||||
* <li>MIME types {@code "application/javascript"}, {@code "application/ecmascript"}, {@code "text/javascript"}, and
|
||||
* {@code "text/ecmascript"};</li>
|
||||
* <li>as well as for the extension {@code "js"}.</li>
|
||||
* </ul>
|
||||
* Programs executing in engines created using {@link #getScriptEngine(String[])} will have the passed arguments
|
||||
* accessible as a global variable named {@code "arguments"}.
|
||||
*/
|
||||
public final class NashornScriptEngineFactory implements ScriptEngineFactory {
|
||||
@Override
|
||||
public String getEngineName() {
|
||||
return (String) getParameter(ScriptEngine.ENGINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEngineVersion() {
|
||||
return (String) getParameter(ScriptEngine.ENGINE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getExtensions() {
|
||||
return Collections.unmodifiableList(extensions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLanguageName() {
|
||||
return (String) getParameter(ScriptEngine.LANGUAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLanguageVersion() {
|
||||
return (String) getParameter(ScriptEngine.LANGUAGE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodCallSyntax(final String obj, final String method, final String... args) {
|
||||
final StringBuilder sb = new StringBuilder().append(obj).append('.').append(method).append('(');
|
||||
final int len = args.length;
|
||||
|
||||
if (len > 0) {
|
||||
sb.append(args[0]);
|
||||
}
|
||||
for (int i = 1; i < len; i++) {
|
||||
sb.append(',').append(args[i]);
|
||||
}
|
||||
sb.append(')');
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMimeTypes() {
|
||||
return Collections.unmodifiableList(mimeTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getNames() {
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOutputStatement(final String toDisplay) {
|
||||
return "print(" + toDisplay + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParameter(final String key) {
|
||||
switch (key) {
|
||||
case ScriptEngine.NAME:
|
||||
return "javascript";
|
||||
case ScriptEngine.ENGINE:
|
||||
return "Oracle Nashorn";
|
||||
case ScriptEngine.ENGINE_VERSION:
|
||||
return Version.version();
|
||||
case ScriptEngine.LANGUAGE:
|
||||
return "ECMAScript";
|
||||
case ScriptEngine.LANGUAGE_VERSION:
|
||||
return "ECMA - 262 Edition 5.1";
|
||||
case "THREADING":
|
||||
// The engine implementation is not thread-safe. Can't be
|
||||
// used to execute scripts concurrently on multiple threads.
|
||||
return null;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid key");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProgram(final String... statements) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (final String statement : statements) {
|
||||
sb.append(statement).append(';');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngine getScriptEngine() {
|
||||
return new NashornScriptEngine(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Script engine initialized by given arguments.
|
||||
*
|
||||
* @param args arguments array passed to script engine.
|
||||
* @return newly created script engine.
|
||||
*/
|
||||
public ScriptEngine getScriptEngine(final String[] args) {
|
||||
return new NashornScriptEngine(this, args);
|
||||
}
|
||||
|
||||
// -- Internals only below this point
|
||||
|
||||
private static final List<String> names;
|
||||
private static final List<String> mimeTypes;
|
||||
private static final List<String> extensions;
|
||||
|
||||
static {
|
||||
names = immutableList(
|
||||
"nashorn", "Nashorn",
|
||||
"js", "JS",
|
||||
"JavaScript", "javascript",
|
||||
"ECMAScript", "ecmascript"
|
||||
);
|
||||
|
||||
mimeTypes = immutableList(
|
||||
"application/javascript",
|
||||
"application/ecmascript",
|
||||
"text/javascript",
|
||||
"text/ecmascript"
|
||||
);
|
||||
|
||||
extensions = immutableList("js");
|
||||
}
|
||||
|
||||
private static List<String> immutableList(final String... elements) {
|
||||
return Collections.unmodifiableList(Arrays.asList(elements));
|
||||
}
|
||||
}
|
||||
323
nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
Normal file
323
nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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. 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.nashorn.api.scripting;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import netscape.javascript.JSObject;
|
||||
|
||||
/**
|
||||
* Mirror object that wraps a given ScriptObject instance. User can
|
||||
* access ScriptObject via the java.util.Map interface.
|
||||
*/
|
||||
final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
|
||||
private final ScriptObject sobj;
|
||||
private final ScriptObject global;
|
||||
|
||||
ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
|
||||
this.sobj = sobj;
|
||||
this.global = global;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other instanceof ScriptObjectMirror) {
|
||||
return sobj.equals(((ScriptObjectMirror)other).sobj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return sobj.hashCode();
|
||||
}
|
||||
|
||||
private <V> V inGlobal(final Callable<V> callable) {
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
final boolean globalChanged = (oldGlobal != global);
|
||||
if (globalChanged) {
|
||||
NashornScriptEngine.setNashornGlobal(global);
|
||||
}
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new AssertionError("Cannot happen", e);
|
||||
} finally {
|
||||
if (globalChanged) {
|
||||
NashornScriptEngine.setNashornGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JSObject methods
|
||||
@Override
|
||||
public Object call(final String methodName, final Object args[]) {
|
||||
final Object val = sobj.get(methodName);
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
final boolean globalChanged = (oldGlobal != global);
|
||||
|
||||
if (val instanceof ScriptFunction) {
|
||||
final Object[] modifiedArgs = unwrapArray(args, global);
|
||||
if (modifiedArgs != null) {
|
||||
for (int i = 0; i < modifiedArgs.length; i++) {
|
||||
final Object arg = modifiedArgs[i];
|
||||
if (arg instanceof ScriptObject) {
|
||||
modifiedArgs[i] = wrap(arg, oldGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (globalChanged) {
|
||||
NashornScriptEngine.setNashornGlobal(global);
|
||||
}
|
||||
return wrap(((ScriptFunction)val).invoke(sobj, modifiedArgs), global);
|
||||
} catch (final RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (final Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
} finally {
|
||||
if (globalChanged) {
|
||||
NashornScriptEngine.setNashornGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("No such method: " + methodName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object eval(final String s) {
|
||||
return inGlobal(new Callable<Object>() {
|
||||
@Override
|
||||
public Object call() {
|
||||
return wrap(global.getContext().eval(global, s, null, null, false), global);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getMember(final String name) {
|
||||
return get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSlot(final int index) {
|
||||
return get(Integer.valueOf(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMember(final String name) {
|
||||
remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMember(final String name, final Object value) {
|
||||
put(name, wrap(value, Context.getGlobal()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSlot(final int index, final Object value) {
|
||||
put(Integer.valueOf(index), wrap(value, Context.getGlobal()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
inGlobal(new Callable<Object>() {
|
||||
@Override public Object call() {
|
||||
sobj.clear();
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(final Object key) {
|
||||
return inGlobal(new Callable<Boolean>() {
|
||||
@Override public Boolean call() {
|
||||
return sobj.containsKey(unwrap(key, global));
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(final Object value) {
|
||||
return inGlobal(new Callable<Boolean>() {
|
||||
@Override public Boolean call() {
|
||||
return sobj.containsValue(unwrap(value, global));
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<Object, Object>> entrySet() {
|
||||
return inGlobal(new Callable<Set<Map.Entry<Object, Object>>>() {
|
||||
@Override public Set<Map.Entry<Object, Object>> call() {
|
||||
final Iterator<String> iter = sobj.propertyIterator();
|
||||
final Set<Map.Entry<Object, Object>> entries = new HashSet<>();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final Object key = wrap(iter.next(), global);
|
||||
final Object value = wrap(sobj.get(key), global);
|
||||
entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(entries);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(final Object key) {
|
||||
return inGlobal(new Callable<Object>() { @Override public Object call() {
|
||||
return wrap(sobj.get(key), global);
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return inGlobal(new Callable<Boolean>() { @Override public Boolean call() {
|
||||
return sobj.isEmpty();
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Object> keySet() {
|
||||
return inGlobal(new Callable<Set<Object>>() { @Override public Set<Object> call() {
|
||||
final Iterator<String> iter = sobj.propertyIterator();
|
||||
final Set<Object> keySet = new HashSet<>();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
keySet.add(wrap(iter.next(), global));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(keySet);
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(final Object key, final Object value) {
|
||||
return inGlobal(new Callable<Object>() {
|
||||
@Override public Object call() {
|
||||
return sobj.put(unwrap(key, global), unwrap(value, global));
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(final Map<?, ?> map) {
|
||||
final boolean strict = sobj.getContext()._strict;
|
||||
inGlobal(new Callable<Object>() { @Override public Object call() {
|
||||
for (final Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
sobj.set(unwrap(entry.getKey(), global), unwrap(entry.getValue(), global), strict);
|
||||
}
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(final Object key) {
|
||||
return inGlobal(new Callable<Object>() {
|
||||
@Override public Object call() {
|
||||
return wrap(sobj.remove(unwrap(key, global)), global);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return inGlobal(new Callable<Integer>() {
|
||||
@Override public Integer call() {
|
||||
return sobj.size();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
return inGlobal(new Callable<Collection<Object>>() { @Override public Collection<Object> call() {
|
||||
final List<Object> values = new ArrayList<>(size());
|
||||
final Iterator<Object> iter = sobj.valueIterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
values.add(wrap(iter.next(), global));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(values);
|
||||
}});
|
||||
}
|
||||
|
||||
static Object wrap(final Object obj, final ScriptObject homeGlobal) {
|
||||
return (obj instanceof ScriptObject) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj;
|
||||
}
|
||||
|
||||
static Object unwrap(final Object obj, final ScriptObject homeGlobal) {
|
||||
if (obj instanceof ScriptObjectMirror) {
|
||||
final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
|
||||
return (mirror.global == homeGlobal)? mirror.sobj : obj;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static Object[] wrapArray(final Object[] args, final ScriptObject homeGlobal) {
|
||||
if (args == null || args.length == 0) {
|
||||
return args;
|
||||
}
|
||||
|
||||
final Object[] newArgs = new Object[args.length];
|
||||
int index = 0;
|
||||
for (final Object obj : args) {
|
||||
newArgs[index] = wrap(obj, homeGlobal);
|
||||
index++;
|
||||
}
|
||||
return newArgs;
|
||||
}
|
||||
|
||||
static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) {
|
||||
if (args == null || args.length == 0) {
|
||||
return args;
|
||||
}
|
||||
|
||||
final Object[] newArgs = new Object[args.length];
|
||||
int index = 0;
|
||||
for (final Object obj : args) {
|
||||
newArgs[index] = unwrap(obj, homeGlobal);
|
||||
index++;
|
||||
}
|
||||
return newArgs;
|
||||
}
|
||||
}
|
||||
38
nashorn/src/jdk/nashorn/api/scripting/package-info.java
Normal file
38
nashorn/src/jdk/nashorn/api/scripting/package-info.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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. 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 package provides the {@code javax.script} integration, which is the preferred way to use Nashorn.
|
||||
* You will ordinarily do this to obtain an instance of a Nashorn script engine:
|
||||
* <pre>
|
||||
* import javax.script.*;
|
||||
* ...
|
||||
* ScriptEngine nashornEngine = new ScriptEngineManager().getEngineByName("Nashorn");
|
||||
* </pre>
|
||||
* <p>Nashorn script engines implement the optional {@link javax.script.Invocable} and {@link javax.script.Compilable}
|
||||
* interfaces, allowing for efficient pre-compilation and repeated execution of scripts. See
|
||||
* {@link jdk.nashorn.api.scripting.NashornScriptEngineFactory} for further details.
|
||||
*/
|
||||
package jdk.nashorn.api.scripting;
|
||||
58
nashorn/src/jdk/nashorn/api/scripting/resources/engine.js
Normal file
58
nashorn/src/jdk/nashorn/api/scripting/resources/engine.js
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This script file is executed by script engine at the construction
|
||||
* of the engine. The functions here assume global variables "context"
|
||||
* of type javax.script.ScriptContext and "engine" of the type
|
||||
* jdk.nashorn.api.scripting.NashornScriptEngine.
|
||||
*
|
||||
**/
|
||||
|
||||
Object.defineProperty(this, "__noSuchProperty__", {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: function (name) {
|
||||
'use strict';
|
||||
return engine.__noSuchProperty__(this, context, name);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(this, "__noSuchMethod__", {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: function (name, args) {
|
||||
'use strict';
|
||||
return engine.__noSuchMethod__(this, context, name, args);
|
||||
}
|
||||
});
|
||||
|
||||
function print(str) {
|
||||
var writer = context.getWriter();
|
||||
if (! (writer instanceof java.io.PrintWriter)) {
|
||||
writer = new java.io.PrintWriter(writer);
|
||||
}
|
||||
writer.println(String(str));
|
||||
}
|
||||
428
nashorn/src/jdk/nashorn/internal/codegen/AccessSpecializer.java
Normal file
428
nashorn/src/jdk/nashorn/internal/codegen/AccessSpecializer.java
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import java.util.HashSet;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.AccessNode;
|
||||
import jdk.nashorn.internal.ir.Assignment;
|
||||
import jdk.nashorn.internal.ir.BinaryNode;
|
||||
import jdk.nashorn.internal.ir.CallNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.IdentNode;
|
||||
import jdk.nashorn.internal.ir.IndexNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.ReferenceNode;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.ir.TypeOverride;
|
||||
import jdk.nashorn.internal.ir.UnaryNode;
|
||||
import jdk.nashorn.internal.ir.VarNode;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
import jdk.nashorn.internal.runtime.Debug;
|
||||
import jdk.nashorn.internal.runtime.DebugLogger;
|
||||
|
||||
/**
|
||||
* This is a post pass for Lower, that removes casts for accessors to objects in
|
||||
* Scope, and replaces the accessor type with a narrower one with possible.
|
||||
*
|
||||
* Any node that implements TypeOverride will be subject to access specialization.
|
||||
*
|
||||
* TypeOverride basically means "type inference has determined that the field x
|
||||
* is an object, but if you do x & 17, it can be read as an int, which we hope
|
||||
* coincides with its internal representation. In that case there is no boxing
|
||||
* that may or may not be removed by the JVM and less data bandwidth.
|
||||
*
|
||||
* Ideally this should not be a post pass, but it requires slot AND scope info, and has
|
||||
* to be run where it is, which is called from {@link CodeGenerator}.
|
||||
*
|
||||
* @see TypeOverride
|
||||
*/
|
||||
|
||||
final class AccessSpecializer extends NodeOperatorVisitor implements Transform {
|
||||
/** Debug logger for access specialization. Enable it with --log=access:level
|
||||
or -Dnashorn.specializations.debug */
|
||||
private static final DebugLogger LOG = new DebugLogger("access", "nashorn.callsiteaccess.debug");
|
||||
private static final boolean DEBUG = LOG.isEnabled();
|
||||
|
||||
@Override
|
||||
public Node enter(final FunctionNode node) {
|
||||
if (node.isTransformApplied(AccessSpecializer.class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final FunctionNode node) {
|
||||
node.registerTransform(AccessSpecializer.class);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final VarNode varNode) {
|
||||
if (varNode.isAssignment()) {
|
||||
return leaveAssign(varNode);
|
||||
}
|
||||
|
||||
return varNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final CallNode callNode) {
|
||||
final Node function = callNode.getFunction();
|
||||
if (function instanceof ReferenceNode) {
|
||||
changeType(callNode, ((ReferenceNode)function).getReference().getType());
|
||||
}
|
||||
return callNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
|
||||
return leaveAssign(binaryNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
|
||||
return propagateResultType(binaryNode, binaryNode.lhs().getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
|
||||
return propagateResultType(binaryNode, binaryNode.rhs().getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveCONVERT(final UnaryNode unaryNode) {
|
||||
final Type castTo = unaryNode.getType();
|
||||
|
||||
Node rhs = unaryNode.rhs();
|
||||
|
||||
// Go through all conversions until we find the first non-convert node.
|
||||
while (rhs.tokenType() == TokenType.CONVERT) {
|
||||
rhs = ((UnaryNode)rhs).rhs();
|
||||
}
|
||||
|
||||
// If this node can be type changed
|
||||
if (canHaveCallSiteType(rhs) && isSupportedCallSiteType(castTo)) {
|
||||
/*
|
||||
* Just add a callsite type and throw away the cast, appropriate
|
||||
* getter/setter is selected, which will do the conversion for us
|
||||
*/
|
||||
changeType(rhs, castTo);
|
||||
fine("*** cast: converting " + debugNode(unaryNode) + " to " + debugNode(rhs));
|
||||
|
||||
return rhs;
|
||||
}
|
||||
|
||||
// Micro optimization for node hygiene and pattern detection - remove unnecessary same type cast
|
||||
if (unaryNode.getType().isEquivalentTo(rhs.getType())) {
|
||||
return rhs;
|
||||
}
|
||||
|
||||
return unaryNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveDECINC(final UnaryNode unaryNode) {
|
||||
assert unaryNode.isAssignment();
|
||||
|
||||
final Node dest = unaryNode.getAssignmentDest();
|
||||
if (canHaveCallSiteType(dest) && isSupportedCallSiteType(unaryNode.getType())) {
|
||||
changeTypeInAssignment(dest, unaryNode.getType());
|
||||
}
|
||||
|
||||
return unaryNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a node that can have its type overridden. This is true for
|
||||
* AccessNodes, IndexNodes and IdentNodes
|
||||
*
|
||||
* @param node the node to check
|
||||
* @return true if node can have a callsite type
|
||||
*/
|
||||
private static boolean canHaveCallSiteType(final Node node) {
|
||||
return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the specialization type supported. Currently we treat booleans as objects
|
||||
* and have no special boolean type accessor, thus booleans are ignored.
|
||||
* TODO - support booleans? NASHORN-590
|
||||
*
|
||||
* @param castTo the type to check
|
||||
* @return true if call site type is supported
|
||||
*/
|
||||
private static boolean isSupportedCallSiteType(final Type castTo) {
|
||||
return castTo.isNumeric(); // don't specializable for boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a node into a covert node
|
||||
*
|
||||
* @param node the node
|
||||
* @return the node as a convert node
|
||||
*/
|
||||
private static Node convert(final Node node) {
|
||||
return new UnaryNode(node.getSource(),
|
||||
Token.recast(node.getToken(), TokenType.CONVERT),
|
||||
node);
|
||||
}
|
||||
|
||||
private static Node leaveAssign(final Node node) {
|
||||
assert node.isAssignment() : node + " is not an assignment";
|
||||
|
||||
|
||||
final Node lhs = ((Assignment<?>)node).getAssignmentDest();
|
||||
Node rhs = ((Assignment<?>)node).getAssignmentSource();
|
||||
|
||||
/**
|
||||
* Nodes with local variable slots are assumed to be of their optimal type
|
||||
* already and aren't affected here. This is not strictly true, for instance
|
||||
* with doubles instead of in a bounded loop. TODO - range check: NASHORN-363
|
||||
*
|
||||
* This is also not strictly true for var y = x = 55; where y has no other uses
|
||||
* Then y can be an int, but lower conservatively does an object of the assign to
|
||||
* scope
|
||||
*/
|
||||
final Symbol lhsSymbol = lhs.getSymbol();
|
||||
|
||||
if (lhsSymbol.hasSlot() && !lhsSymbol.isScope()) {
|
||||
finest(lhs.getSymbol() + " has slot!");
|
||||
if (!lhs.getType().isEquivalentTo(rhs.getType())) {
|
||||
finest("\tslot assignment: " +lhs.getType()+ " " +rhs.getType() + " " + debugNode(node));
|
||||
|
||||
final Node c = convert(rhs);
|
||||
c.setSymbol(lhsSymbol);
|
||||
((Assignment<?>)node).setAssignmentSource(c);
|
||||
|
||||
fine("*** slot assignment turned to : " + debugNode(node));
|
||||
} else {
|
||||
finest("aborted - type equivalence between lhs and rhs");
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// e.g. __DIR__, __LINE__, __FILE__ - don't try to change these
|
||||
if (lhs instanceof IdentNode && ((IdentNode)lhs).isSpecialIdentity()) {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to cast to the type of the right hand side, now pruned. E.g. an (object)17 should
|
||||
* now be just 17, an int.
|
||||
*/
|
||||
Type castTo = rhs.getType();
|
||||
|
||||
// If LHS can't get a new type, neither can rhs - retain the convert
|
||||
if (!canHaveCallSiteType(lhs)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
// Take the narrowest type of the entire cast sequence
|
||||
while (rhs.tokenType() == TokenType.CONVERT) {
|
||||
rhs = ((UnaryNode)rhs).rhs();
|
||||
castTo = Type.narrowest(rhs.getType(), castTo); //e.g. (object)(int) -> int even though object is outermost
|
||||
}
|
||||
|
||||
// If castTo is wider than widestOperationType, castTo can be further slowed down
|
||||
final Type widestOperationType = node.getWidestOperationType();
|
||||
finest("node wants to be " + castTo + " and its widest operation is " + widestOperationType);
|
||||
|
||||
if (widestOperationType != castTo && Type.widest(castTo, widestOperationType) == castTo) {
|
||||
info("###" + node + " castTo was " + castTo + " but could be downgraded to " + node.getWidestOperationType());
|
||||
castTo = node.getWidestOperationType();
|
||||
if (rhs instanceof TypeOverride) {
|
||||
changeType(rhs, castTo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a self modifying op, we can't be narrower than the widest optype
|
||||
* or e.g. x = x + 12 and x += 12 will turn into different things
|
||||
*/
|
||||
if (node.isSelfModifying()) {
|
||||
castTo = Type.widest(widestOperationType, castTo);
|
||||
}
|
||||
|
||||
// We only specialize for numerics, not for booleans.
|
||||
if (isSupportedCallSiteType(castTo)) {
|
||||
if (rhs.getType() != castTo) {
|
||||
finest("cast was necessary, abort: " + node + " " + rhs.getType() + " != " + castTo);
|
||||
return node;
|
||||
}
|
||||
|
||||
finest("assign: " + debugNode(node));
|
||||
|
||||
changeTypeInAssignment(lhs, castTo);
|
||||
((Assignment<?>)node).setAssignmentSource(rhs);
|
||||
|
||||
info("### modified to " + debugNode(node) + " (given type override " + castTo + ")");
|
||||
|
||||
propagateResultType(node, castTo);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static Node propagateResultType(final Node node, final Type type) {
|
||||
//warning! this CANNOT be done for non temporaries as they are used in other computations
|
||||
if (isSupportedCallSiteType(type)) {
|
||||
if (node.getSymbol().isTemp()) {
|
||||
finest("changing temporary type: " + debugNode(node) + " to " + type);
|
||||
node.getSymbol().setTypeOverride(type);
|
||||
info("### node modified to " + debugNode(node) + " (given type override " + type + ")");
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private static void changeTypeInAssignment(final Node dest, final Type newType) {
|
||||
if (changeType(dest, newType)) {
|
||||
finest("changed assignment " + dest + " " + dest.getSymbol());
|
||||
assert !newType.isObject();
|
||||
|
||||
final HashSet<Node> exclude = new HashSet<>();
|
||||
|
||||
dest.accept(new NodeVisitor() {
|
||||
|
||||
private void setCanBePrimitive(final Symbol symbol) {
|
||||
fine("*** can be primitive symbol " + symbol + " " + Debug.id(symbol));
|
||||
symbol.setCanBePrimitive(newType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final IdentNode identNode) {
|
||||
if (!exclude.contains(identNode)) {
|
||||
setCanBePrimitive(identNode.getSymbol());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final AccessNode accessNode) {
|
||||
setCanBePrimitive(accessNode.getProperty().getSymbol());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final IndexNode indexNode) {
|
||||
exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine
|
||||
return indexNode;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean changeType(final Node node, final Type newType) {
|
||||
if (!node.getType().equals(newType)) {
|
||||
((TypeOverride)node).setType(newType);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String debugNode(final Node node) {
|
||||
if (DEBUG) {
|
||||
return node.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static void info(final String str) {
|
||||
LOG.info(str);
|
||||
}
|
||||
|
||||
private static void fine(final String str) {
|
||||
LOG.fine(str);
|
||||
}
|
||||
|
||||
private static void finest(final String str) {
|
||||
LOG.finest(str);
|
||||
}
|
||||
|
||||
}
|
||||
199
nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
Normal file
199
nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.EQ;
|
||||
import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.GE;
|
||||
import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.GT;
|
||||
import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.LE;
|
||||
import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.LT;
|
||||
import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.NE;
|
||||
|
||||
import jdk.nashorn.internal.codegen.MethodEmitter.Label;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.BinaryNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.TernaryNode;
|
||||
import jdk.nashorn.internal.ir.UnaryNode;
|
||||
|
||||
/**
|
||||
* Branch optimizer for CodeGenerator. Given a jump condition this helper
|
||||
* class attempts to simplify the control flow
|
||||
*/
|
||||
final class BranchOptimizer {
|
||||
|
||||
private final CodeGenerator codegen;
|
||||
private final MethodEmitter method;
|
||||
|
||||
BranchOptimizer(final CodeGenerator codegen, final MethodEmitter method) {
|
||||
this.codegen = codegen;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
void execute(final Node node, final Label label, final boolean state) {
|
||||
branchOptimizer(node, label, state);
|
||||
}
|
||||
|
||||
private void load(final Node node) {
|
||||
codegen.load(node);
|
||||
}
|
||||
|
||||
private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) {
|
||||
final Node rhs = unaryNode.rhs();
|
||||
|
||||
switch (unaryNode.tokenType()) {
|
||||
case NOT:
|
||||
branchOptimizer(rhs, label, !state);
|
||||
return;
|
||||
case CONVERT:
|
||||
if (unaryNode.getType().isBoolean()) {
|
||||
branchOptimizer(rhs, label, state);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// convert to boolean
|
||||
load(unaryNode);
|
||||
method.convert(Type.BOOLEAN);
|
||||
if (state) {
|
||||
method.ifne(label);
|
||||
} else {
|
||||
method.ifeq(label);
|
||||
}
|
||||
}
|
||||
|
||||
private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) {
|
||||
final Node lhs = binaryNode.lhs();
|
||||
final Node rhs = binaryNode.rhs();
|
||||
|
||||
switch (binaryNode.tokenType()) {
|
||||
case AND:
|
||||
if (state) {
|
||||
final Label skip = new Label("skip");
|
||||
branchOptimizer(lhs, skip, false);
|
||||
branchOptimizer(rhs, label, true);
|
||||
method.label(skip);
|
||||
} else {
|
||||
branchOptimizer(lhs, label, false);
|
||||
branchOptimizer(rhs, label, false);
|
||||
}
|
||||
return;
|
||||
|
||||
case OR:
|
||||
if (state) {
|
||||
branchOptimizer(lhs, label, true);
|
||||
branchOptimizer(rhs, label, true);
|
||||
} else {
|
||||
final Label skip = new Label("skip");
|
||||
branchOptimizer(lhs, skip, true);
|
||||
branchOptimizer(rhs, label, false);
|
||||
method.label(skip);
|
||||
}
|
||||
return;
|
||||
|
||||
case EQ:
|
||||
case EQ_STRICT:
|
||||
assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
|
||||
load(lhs);
|
||||
load(rhs);
|
||||
method.conditionalJump(state ? EQ : NE, true, label);
|
||||
return;
|
||||
|
||||
case NE:
|
||||
case NE_STRICT:
|
||||
assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
|
||||
load(lhs);
|
||||
load(rhs);
|
||||
method.conditionalJump(state ? NE : EQ, true, label);
|
||||
return;
|
||||
|
||||
case GE:
|
||||
assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
|
||||
load(lhs);
|
||||
load(rhs);
|
||||
method.conditionalJump(state ? GE : LT, !state, label);
|
||||
return;
|
||||
|
||||
case GT:
|
||||
assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
|
||||
load(lhs);
|
||||
load(rhs);
|
||||
method.conditionalJump(state ? GT : LE, !state, label);
|
||||
return;
|
||||
|
||||
case LE:
|
||||
assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
|
||||
load(lhs);
|
||||
load(rhs);
|
||||
method.conditionalJump(state ? LE : GT, state, label);
|
||||
return;
|
||||
|
||||
case LT:
|
||||
assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol() + " in " + binaryNode;
|
||||
load(lhs);
|
||||
load(rhs);
|
||||
method.conditionalJump(state ? LT : GE, state, label);
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
load(binaryNode);
|
||||
method.convert(Type.BOOLEAN);
|
||||
if (state) {
|
||||
method.ifne(label);
|
||||
} else {
|
||||
method.ifeq(label);
|
||||
}
|
||||
}
|
||||
|
||||
private void branchOptimizer(final Node node, final Label label, final boolean state) {
|
||||
if (!(node instanceof TernaryNode)) {
|
||||
|
||||
if (node instanceof BinaryNode) {
|
||||
branchOptimizer((BinaryNode)node, label, state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node instanceof UnaryNode) {
|
||||
branchOptimizer((UnaryNode)node, label, state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
load(node);
|
||||
method.convert(Type.BOOLEAN);
|
||||
if (state) {
|
||||
method.ifne(label);
|
||||
} else {
|
||||
method.ifeq(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
620
nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java
Normal file
620
nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java
Normal file
@ -0,0 +1,620 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEINTERFACE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESPECIAL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.H_NEWINVOKESPECIAL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.CLINIT;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.GET_ARRAY_PREFIX;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.GET_ARRAY_SUFFIX;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.INIT;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.SET_MAP;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.className;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* The interface responsible for speaking to ASM, emitting classes,
|
||||
* fields and methods.
|
||||
* <p>
|
||||
* This file contains the ClassEmitter, which is the master object
|
||||
* responsible for writing byte codes. It utilizes a MethodEmitter
|
||||
* for method generation, which also the NodeVisitors own, to keep
|
||||
* track of the current code generator and what it is doing.
|
||||
* <p>
|
||||
* There is, however, nothing stopping you from using this in a
|
||||
* completely self contained environment, for example in ObjectGenerator
|
||||
* where there are no visitors or external hooks.
|
||||
* <p>
|
||||
* MethodEmitter makes it simple to generate code for methods without
|
||||
* having to do arduous type checking. It maintains a type stack
|
||||
* and will pick the appropriate operation for all operations sent to it
|
||||
* We also allow chained called to a MethodEmitter for brevity, e.g.
|
||||
* it is legal to write _new(className).dup() or
|
||||
* load(slot).load(slot2).xor().store(slot3);
|
||||
* <p>
|
||||
* If running with assertions enabled, any type conflict, such as different
|
||||
* bytecode stack sizes or operating on the wrong type will be detected
|
||||
* and an error thrown.
|
||||
* <p>
|
||||
* There is also a very nice debug interface that can emit formatted
|
||||
* bytecodes that have been written. This is enabled by setting the
|
||||
* environment "nashorn.codegen.debug" to true, or --log=codegen:<level>
|
||||
* <p>
|
||||
* A ClassEmitter implements an Emitter - i.e. it needs to have
|
||||
* well defined start and end calls for whatever it is generating. Assertions
|
||||
* detect if this is not true
|
||||
*
|
||||
* @see Compiler
|
||||
* @see CodeGenerator
|
||||
*/
|
||||
public class ClassEmitter implements Emitter {
|
||||
|
||||
/** Sanity check flag - have we started on a class? */
|
||||
private boolean classStarted;
|
||||
|
||||
/** Sanity check flag - have we ended this emission? */
|
||||
private boolean classEnded;
|
||||
|
||||
/**
|
||||
* Sanity checks - which methods have we currently
|
||||
* started for generation in this class?
|
||||
*/
|
||||
private final HashSet<MethodEmitter> methodsStarted;
|
||||
|
||||
/** The ASM classwriter that we use for all bytecode operations */
|
||||
protected final ClassWriter cw;
|
||||
|
||||
/** The context */
|
||||
protected final Context context;
|
||||
|
||||
/** Default flags for class generation - oublic class */
|
||||
private static final EnumSet<Flag> DEFAULT_METHOD_FLAGS = EnumSet.of(Flag.PUBLIC);
|
||||
|
||||
/** Compile unit class name. */
|
||||
private String unitClassName;
|
||||
|
||||
/** Set of constants access methods required. */
|
||||
private Set<Class<?>> constantMethodNeeded;
|
||||
|
||||
/**
|
||||
* Constructor - only used internally in this class as it breaks
|
||||
* abstraction towards ASM or other code generator below
|
||||
*
|
||||
* @param context context
|
||||
* @param cw ASM classwriter
|
||||
*/
|
||||
private ClassEmitter(final Context context, final ClassWriter cw) {
|
||||
assert context != null;
|
||||
|
||||
this.context = context;
|
||||
this.cw = cw;
|
||||
this.methodsStarted = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context context
|
||||
* @param className name of class to weave
|
||||
* @param superClassName super class name for class
|
||||
* @param interfaceNames names of interfaces implemented by this class, or null if none
|
||||
*/
|
||||
public ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) {
|
||||
this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
|
||||
cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClassName, interfaceNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor from the compiler
|
||||
*
|
||||
* @param compiler Compiler
|
||||
* @param unitClassName Compile unit class name.
|
||||
* @param strictMode Should we generate this method in strict mode
|
||||
*/
|
||||
ClassEmitter(final Compiler compiler, final String unitClassName, final boolean strictMode) {
|
||||
this(compiler.getContext(),
|
||||
new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
|
||||
private static final String OBJECT_CLASS = "java/lang/Object";
|
||||
|
||||
@Override
|
||||
protected String getCommonSuperClass(final String type1, final String type2) {
|
||||
try {
|
||||
return super.getCommonSuperClass(type1, type2);
|
||||
} catch (final RuntimeException e) {
|
||||
if (isScriptObject(Compiler.SCRIPTS_PACKAGE, type1) && isScriptObject(Compiler.SCRIPTS_PACKAGE, type2)) {
|
||||
return className(ScriptObject.class);
|
||||
}
|
||||
return OBJECT_CLASS;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.unitClassName = unitClassName;
|
||||
this.constantMethodNeeded = new HashSet<>();
|
||||
|
||||
cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, unitClassName, null, Compiler.pathName(jdk.nashorn.internal.scripts.JS$.class.getName()), null);
|
||||
cw.visitSource(compiler.getSource().getName(), null);
|
||||
|
||||
defineCommonStatics(strictMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the static fields common in all scripts.
|
||||
* @param strictMode Should we generate this method in strict mode
|
||||
*/
|
||||
private void defineCommonStatics(final boolean strictMode) {
|
||||
// source - used to store the source data (text) for this script. Shared across
|
||||
// compile units. Set externally by the compiler.
|
||||
field(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SOURCE.tag(), Source.class);
|
||||
|
||||
// constants - used to the constants array for this script. Shared across
|
||||
// compile units. Set externally by the compiler.
|
||||
field(EnumSet.of(Flag.PUBLIC, Flag.STATIC), CONSTANTS.tag(), Object[].class);
|
||||
|
||||
// strictMode - was this script compiled in strict mode. Set externally by the compiler.
|
||||
field(EnumSet.of(Flag.PUBLIC, Flag.STATIC, Flag.FINAL), STRICT_MODE.tag(), boolean.class, strictMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define static utilities common needed in scripts. These are per compile unit
|
||||
* and therefore have to be defined here and not in code gen.
|
||||
*/
|
||||
private void defineCommonUtilities() {
|
||||
assert unitClassName != null;
|
||||
|
||||
if (constantMethodNeeded.contains(String.class)) {
|
||||
// $getString - get the ith entry from the constants table and cast to String.
|
||||
final MethodEmitter getStringMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), GET_STRING.tag(), String.class, int.class);
|
||||
getStringMethod.begin();
|
||||
getStringMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor())
|
||||
.load(Type.INT, 0)
|
||||
.arrayload()
|
||||
.checkcast(String.class)
|
||||
._return();
|
||||
getStringMethod.end();
|
||||
}
|
||||
|
||||
if (constantMethodNeeded.contains(PropertyMap.class)) {
|
||||
// $getMap - get the ith entry from the constants table and cast to PropertyMap.
|
||||
final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class);
|
||||
getMapMethod.begin();
|
||||
getMapMethod.loadConstants(unitClassName)
|
||||
.load(Type.INT, 0)
|
||||
.arrayload()
|
||||
.checkcast(PropertyMap.class)
|
||||
._return();
|
||||
getMapMethod.end();
|
||||
|
||||
// $setMap - overwrite an existing map.
|
||||
final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class);
|
||||
setMapMethod.begin();
|
||||
setMapMethod.loadConstants(unitClassName)
|
||||
.load(Type.INT, 0)
|
||||
.load(Type.OBJECT, 1)
|
||||
.arraystore();
|
||||
setMapMethod.returnVoid();
|
||||
setMapMethod.end();
|
||||
}
|
||||
|
||||
// $getXXXX$array - get the ith entry from the constants table and cast to XXXX[].
|
||||
for (final Class<?> cls : constantMethodNeeded) {
|
||||
if (cls.isArray()) {
|
||||
defineGetArrayMethod(cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a primitive specific method for getting the ith entry from the constants table and cast.
|
||||
* @param cls Array class.
|
||||
*/
|
||||
private void defineGetArrayMethod(final Class<?> cls) {
|
||||
assert unitClassName != null;
|
||||
|
||||
final String methodName = getArrayMethodName(cls);
|
||||
final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class);
|
||||
|
||||
getArrayMethod.begin();
|
||||
getArrayMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor())
|
||||
.load(Type.INT, 0)
|
||||
.arrayload()
|
||||
.checkcast(cls)
|
||||
.dup()
|
||||
.arraylength()
|
||||
.invoke(staticCallNoLookup(Arrays.class, "copyOf", cls, cls, int.class))
|
||||
._return();
|
||||
getArrayMethod.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the name of a get array from constant pool method.
|
||||
* @param cls Name of array class.
|
||||
* @return Method name.
|
||||
*/
|
||||
static String getArrayMethodName(final Class<?> cls) {
|
||||
assert cls.isArray();
|
||||
return GET_ARRAY_PREFIX.tag() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.tag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a get constant method is issued for the class.
|
||||
* @param cls Class of constant.
|
||||
*/
|
||||
public void needGetConstantMethod(final Class<?> cls) {
|
||||
constantMethodNeeded.add(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspect class name and decide whether we are generating a ScriptObject class
|
||||
*
|
||||
* @param scriptPrefix the script class prefix for the current script
|
||||
* @param type the type to check
|
||||
*
|
||||
* @return true if type is ScriptObject
|
||||
*/
|
||||
private static boolean isScriptObject(final String scriptPrefix, final String type) {
|
||||
if (type.startsWith(scriptPrefix)) {
|
||||
return true;
|
||||
} else if (type.equals(CompilerConstants.className(ScriptObject.class))) {
|
||||
return true;
|
||||
} else if (type.startsWith(Compiler.OBJECTS_PACKAGE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call at beginning of class emission
|
||||
* @see Emitter
|
||||
*/
|
||||
@Override
|
||||
public void begin() {
|
||||
classStarted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call at end of class emission
|
||||
* @see Emitter
|
||||
*/
|
||||
@Override
|
||||
public void end() {
|
||||
assert classStarted;
|
||||
|
||||
if (unitClassName != null) {
|
||||
defineCommonUtilities();
|
||||
}
|
||||
|
||||
cw.visitEnd();
|
||||
classStarted = false;
|
||||
classEnded = true;
|
||||
assert methodsStarted.isEmpty() : "methodsStarted not empty " + methodsStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassemble an array of byte code.
|
||||
*
|
||||
* @param context the context
|
||||
* @param bytecode byte array representing bytecode
|
||||
*/
|
||||
public static void disassemble(final Context context, final byte[] bytecode) {
|
||||
new ClassReader(bytecode).accept(new TraceClassVisitor(context.getErr()), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify an array of byte code as a valid Java class
|
||||
*
|
||||
* @param context the context
|
||||
* @param bytecode the bytecode array
|
||||
*/
|
||||
public static void verify(final Context context, final byte[] bytecode) {
|
||||
context.verify(bytecode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return context used for class emission
|
||||
*/
|
||||
Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call back from MethodEmitter for method start
|
||||
*
|
||||
* @see MethodEmitter
|
||||
*
|
||||
* @param method method emitter.
|
||||
*/
|
||||
void beginMethod(final MethodEmitter method) {
|
||||
assert !methodsStarted.contains(method);
|
||||
methodsStarted.add(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call back from MethodEmitter for method end
|
||||
*
|
||||
* @see MethodEmitter
|
||||
*
|
||||
* @param method
|
||||
*/
|
||||
void endMethod(final MethodEmitter method) {
|
||||
assert methodsStarted.contains(method);
|
||||
methodsStarted.remove(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new method to the class - defaults to public method
|
||||
*
|
||||
* @param methodName name of method
|
||||
* @param rtype return type of the method
|
||||
* @param ptypes parameter types the method
|
||||
*
|
||||
* @return method emitter to use for weaving this method
|
||||
*/
|
||||
public MethodEmitter method(final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return method(DEFAULT_METHOD_FLAGS, methodName, rtype, ptypes); //TODO why public default ?
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new method to the class - defaults to public method
|
||||
*
|
||||
* @param methodFlags access flags for the method
|
||||
* @param methodName name of method
|
||||
* @param rtype return type of the method
|
||||
* @param ptypes parameter types the method
|
||||
*
|
||||
* @return method emitter to use for weaving this method
|
||||
*/
|
||||
public MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, methodDescriptor(rtype, ptypes), null, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new method to the class - defaults to public method
|
||||
*
|
||||
* @param methodName name of method
|
||||
* @param descriptor descriptor of method
|
||||
*
|
||||
* @return method emitter to use for weaving this method
|
||||
*/
|
||||
public MethodEmitter method(final String methodName, final String descriptor) {
|
||||
return method(DEFAULT_METHOD_FLAGS, methodName, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new method to the class - defaults to public method
|
||||
*
|
||||
* @param methodFlags access flags for the method
|
||||
* @param methodName name of method
|
||||
* @param descriptor descriptor of method
|
||||
*
|
||||
* @return method emitter to use for weaving this method
|
||||
*/
|
||||
public MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final String descriptor) {
|
||||
return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new method to the class, representing a function node
|
||||
*
|
||||
* @param functionNode the function node to generate a method for
|
||||
* @return method emitter to use for weaving this method
|
||||
*/
|
||||
public MethodEmitter method(final FunctionNode functionNode) {
|
||||
final MethodVisitor mv = cw.visitMethod(
|
||||
ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0),
|
||||
functionNode.getName(),
|
||||
FunctionSignature.functionSignature(functionNode),
|
||||
null,
|
||||
null);
|
||||
|
||||
return new MethodEmitter(this, mv, functionNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start generating the <clinit> method in the class
|
||||
*
|
||||
* @return method emitter to use for weaving <clinit>
|
||||
*/
|
||||
public MethodEmitter clinit() {
|
||||
return method(EnumSet.of(Flag.STATIC), CLINIT.tag(), void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start generating an <init>()V method in the class
|
||||
*
|
||||
* @return method emitter to use for weaving <init>()V
|
||||
*/
|
||||
public MethodEmitter init() {
|
||||
return method(INIT.tag(), void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start generating an <init>()V method in the class
|
||||
*
|
||||
* @param ptypes parameter types for constructor
|
||||
* @return method emitter to use for weaving <init>()V
|
||||
*/
|
||||
public MethodEmitter init(final Class<?>... ptypes) {
|
||||
return method(INIT.tag(), void.class, ptypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start generating an <init>(...)V method in the class
|
||||
*
|
||||
* @param flags access flags for the constructor
|
||||
* @param ptypes parameter types for the constructor
|
||||
*
|
||||
* @return method emitter to use for weaving <init>(...)V
|
||||
*/
|
||||
public MethodEmitter init(final EnumSet<Flag> flags, final Class<?>... ptypes) {
|
||||
return method(flags, INIT.tag(), void.class, ptypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the class, initialized to a value
|
||||
*
|
||||
* @param fieldFlags flags, e.g. should it be static or public etc
|
||||
* @param fieldName name of field
|
||||
* @param fieldType the type of the field
|
||||
* @param value the value
|
||||
*
|
||||
* @see ClassEmitter.Flag
|
||||
*/
|
||||
public final void field(final EnumSet<Flag> fieldFlags, final String fieldName, final Class<?> fieldType, final Object value) {
|
||||
cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the class
|
||||
*
|
||||
* @param fieldFlags access flags for the field
|
||||
* @param fieldName name of field
|
||||
* @param fieldType type of the field
|
||||
*
|
||||
* @see ClassEmitter.Flag
|
||||
*/
|
||||
public final void field(final EnumSet<Flag> fieldFlags, final String fieldName, final Class<?> fieldType) {
|
||||
field(fieldFlags, fieldName, fieldType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the class - defaults to public
|
||||
*
|
||||
* @param fieldName name of field
|
||||
* @param fieldType type of field
|
||||
*/
|
||||
public final void field(final String fieldName, final Class<?> fieldType) {
|
||||
field(EnumSet.of(Flag.PUBLIC), fieldName, fieldType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a bytecode array from this ClassEmitter. The ClassEmitter must
|
||||
* have been ended (having its end function called) for this to work.
|
||||
*
|
||||
* @return byte code array for generated class, null if class generation hasn't been ended with {@link ClassEmitter#end()}
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
assert classEnded;
|
||||
if (!classEnded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstraction for flags used in class emission
|
||||
*
|
||||
* We provide abstraction separating these from the underlying bytecode
|
||||
* emitter.
|
||||
*
|
||||
* Flags are provided for method handles, protection levels, static/virtual
|
||||
* fields/methods.
|
||||
*/
|
||||
public static enum Flag {
|
||||
/** method handle with static access */
|
||||
HANDLE_STATIC(H_INVOKESTATIC),
|
||||
/** method handle with new invoke special access */
|
||||
HANDLE_NEWSPECIAL(H_NEWINVOKESPECIAL),
|
||||
/** method handle with invoke special access */
|
||||
HANDLE_SPECIAL(H_INVOKESPECIAL),
|
||||
/** method handle with invoke virtual access */
|
||||
HANDLE_VIRTUAL(H_INVOKEVIRTUAL),
|
||||
/** method handle with invoke interface access */
|
||||
HANDLE_INTERFACE(H_INVOKEINTERFACE),
|
||||
|
||||
/** final access */
|
||||
FINAL(ACC_FINAL),
|
||||
/** static access */
|
||||
STATIC(ACC_STATIC),
|
||||
/** public access */
|
||||
PUBLIC(ACC_PUBLIC),
|
||||
/** private access */
|
||||
PRIVATE(ACC_PRIVATE);
|
||||
|
||||
private int value;
|
||||
|
||||
private Flag(final int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of this flag
|
||||
* @return the int value
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the corresponding ASM flag value for an enum set of flags
|
||||
*
|
||||
* @param flags enum set of flags
|
||||
* @return an integer value representing the flags intrinsic values or:ed together
|
||||
*/
|
||||
public static int getValue(final EnumSet<Flag> flags) {
|
||||
int v = 0;
|
||||
for (final Flag flag : flags) {
|
||||
v |= flag.getValue();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
3266
nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
Normal file
3266
nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
Normal file
File diff suppressed because it is too large
Load Diff
95
nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java
Normal file
95
nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
/**
|
||||
* Used to track split class compilation.
|
||||
*/
|
||||
public class CompileUnit {
|
||||
/** Current class name */
|
||||
private final String className;
|
||||
|
||||
/** Current class generator */
|
||||
private final ClassEmitter classEmitter;
|
||||
|
||||
private long weight;
|
||||
|
||||
CompileUnit(final String className, final ClassEmitter classEmitter) {
|
||||
this(className, classEmitter, 0L);
|
||||
}
|
||||
|
||||
CompileUnit(final String className, final ClassEmitter classEmitter, final long initialWeight) {
|
||||
this.className = className;
|
||||
this.classEmitter = classEmitter;
|
||||
this.weight = initialWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add weight to this compile unit
|
||||
* @param w weight to add
|
||||
*/
|
||||
public void addWeight(final long w) {
|
||||
this.weight += w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current weight of the compile unit.
|
||||
* @return the unit's weight
|
||||
*/
|
||||
public long getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this compile unit can hold {@code weight} more units of weight
|
||||
* @param w weight to check if can be added
|
||||
* @return true if weight fits in this compile unit
|
||||
*/
|
||||
public boolean canHold(final long w) {
|
||||
return (this.weight + w) < Splitter.SPLIT_THRESHOLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class emitter for this compile unit
|
||||
* @return class emitter
|
||||
*/
|
||||
public ClassEmitter getClassEmitter() {
|
||||
return classEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class name for this compile unit
|
||||
* @return the class name
|
||||
*/
|
||||
public String getUnitClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[classname=" + className + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
|
||||
}
|
||||
}
|
||||
685
nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
Normal file
685
nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
Normal file
@ -0,0 +1,685 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.DEFAULT_SCRIPT_NAME;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.debug.ASTWriter;
|
||||
import jdk.nashorn.internal.ir.debug.PrintVisitor;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.Parser;
|
||||
import jdk.nashorn.internal.runtime.CodeInstaller;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.DebugLogger;
|
||||
import jdk.nashorn.internal.runtime.ECMAErrors;
|
||||
import jdk.nashorn.internal.runtime.ErrorManager;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
import jdk.nashorn.internal.runtime.linker.Mangler;
|
||||
import jdk.nashorn.internal.runtime.options.Options;
|
||||
|
||||
/**
|
||||
* Responsible for converting JavaScripts to java byte code. Main entry
|
||||
* point for code generator
|
||||
*/
|
||||
public final class Compiler {
|
||||
|
||||
/** Compiler states available */
|
||||
public enum State {
|
||||
/** compiler is ready */
|
||||
INITIALIZED,
|
||||
/** method has been parsed */
|
||||
PARSED,
|
||||
/** method has been lowered */
|
||||
LOWERED,
|
||||
/** method has been emitted to bytecode */
|
||||
EMITTED
|
||||
}
|
||||
|
||||
/** Current context */
|
||||
private final Context context;
|
||||
|
||||
/** Currently compiled source */
|
||||
private final Source source;
|
||||
|
||||
/** Current error manager */
|
||||
private final ErrorManager errors;
|
||||
|
||||
/** Names uniqueName for this compile. */
|
||||
private final Namespace namespace;
|
||||
|
||||
/** Current function node, or null if compiling from source until parsed */
|
||||
private FunctionNode functionNode;
|
||||
|
||||
/** Current compiler state */
|
||||
private final EnumSet<State> state;
|
||||
|
||||
/** Name of the scripts package */
|
||||
public static final String SCRIPTS_PACKAGE = "jdk/nashorn/internal/scripts";
|
||||
|
||||
/** Name of the objects package */
|
||||
public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects";
|
||||
|
||||
/** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */
|
||||
public static final String GLOBAL_OBJECT = OBJECTS_PACKAGE + '/' + "Global";
|
||||
|
||||
/** Name of the ScriptObjectImpl, cannot be referred to as .class @see FunctionObjectCreator */
|
||||
public static final String SCRIPTOBJECT_IMPL_OBJECT = OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl";
|
||||
|
||||
/** Name of the Trampoline, cannot be referred to as .class @see FunctionObjectCreator */
|
||||
public static final String TRAMPOLINE_OBJECT = OBJECTS_PACKAGE + '/' + "Trampoline";
|
||||
|
||||
/** Compile unit (class) table. */
|
||||
private final Set<CompileUnit> compileUnits;
|
||||
|
||||
/** All the "complex" constants used in the code. */
|
||||
private final ConstantData constantData;
|
||||
|
||||
static final DebugLogger LOG = new DebugLogger("compiler");
|
||||
|
||||
/** Script name */
|
||||
private String scriptName;
|
||||
|
||||
/** Should we dump classes to disk and compile only? */
|
||||
private final boolean dumpClass;
|
||||
|
||||
/** Code map class name -> byte code for all classes generated from this Source or FunctionNode */
|
||||
private Map<String, byte[]> code;
|
||||
|
||||
/** Are we compiling in strict mode? */
|
||||
private boolean strict;
|
||||
|
||||
/** Is this a lazy compilation - i.e. not from source, but jitting a previously parsed FunctionNode? */
|
||||
private boolean isLazy;
|
||||
|
||||
/** Lazy jitting is disabled by default */
|
||||
private static final boolean LAZY_JIT = false;
|
||||
|
||||
/**
|
||||
* Should we use integers for literals and all operations
|
||||
* that are based in constant and parameter assignment as
|
||||
* long as they can be proven not to overflow? With this enabled
|
||||
* var x = 17 would tag x as an integer, rather than a double,
|
||||
* but as soon as it is used in an operation that may potentially
|
||||
* overflow, such as an add, we conservatively widen it to double
|
||||
* (number type). This is because overflow checks in the code
|
||||
* are likely much more expensive that method specialization
|
||||
*
|
||||
* @return true if numbers should start as ints, false if they should
|
||||
* start as doubles
|
||||
*/
|
||||
static boolean shouldUseIntegers() {
|
||||
return USE_INTS;
|
||||
}
|
||||
|
||||
private static final boolean USE_INTS;
|
||||
|
||||
/**
|
||||
* Should we use integers for arithmetic operations as well?
|
||||
* TODO: We currently generate no overflow checks so this is
|
||||
* disabled
|
||||
*
|
||||
* @see #shouldUseIntegers()
|
||||
*
|
||||
* @return true if arithmetic operations should not widen integer
|
||||
* operands by default.
|
||||
*/
|
||||
static boolean shouldUseIntegerArithmetic() {
|
||||
return Compiler.shouldUseIntegers() && USE_INT_ARITH;
|
||||
}
|
||||
|
||||
private static final boolean USE_INT_ARITH;
|
||||
|
||||
static {
|
||||
USE_INTS = !Options.getBooleanProperty("nashorn.compiler.ints.disable");
|
||||
USE_INT_ARITH = Options.getBooleanProperty("nashorn.compiler.intarithmetic");
|
||||
|
||||
assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for compiler that should compile from source to bytecode
|
||||
*
|
||||
* @param source the source
|
||||
* @param context context
|
||||
*
|
||||
* @return compiler instance
|
||||
*/
|
||||
public static Compiler compiler(final Source source, final Context context) {
|
||||
return Compiler.compiler(source, context, context.getErrors(), context._strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to get a compiler that goes from from source to bytecode
|
||||
*
|
||||
* @param source source code
|
||||
* @param context context
|
||||
* @param errors error manager
|
||||
* @param strict compilation in strict mode?
|
||||
*
|
||||
* @return compiler instance
|
||||
*/
|
||||
public static Compiler compiler(final Source source, final Context context, final ErrorManager errors, final boolean strict) {
|
||||
return new Compiler(source, context, errors, strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to get a compiler that goes from FunctionNode (parsed) to bytecode
|
||||
* Requires previous compiler for state
|
||||
*
|
||||
* @param compiler primordial compiler
|
||||
* @param functionNode functionNode to compile
|
||||
*
|
||||
* @return compiler
|
||||
*/
|
||||
public static Compiler compiler(final Compiler compiler, final FunctionNode functionNode) {
|
||||
assert false : "lazy jit - not implemented";
|
||||
final Compiler newCompiler = new Compiler(compiler);
|
||||
newCompiler.state.add(State.PARSED);
|
||||
newCompiler.functionNode = functionNode;
|
||||
newCompiler.isLazy = true;
|
||||
return compiler;
|
||||
}
|
||||
|
||||
private Compiler(final Compiler compiler) {
|
||||
this(compiler.source, compiler.context, compiler.errors, compiler.strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source to compile
|
||||
* @param context context
|
||||
* @param errors error manager
|
||||
* @param strict compile in strict mode
|
||||
*/
|
||||
private Compiler(final Source source, final Context context, final ErrorManager errors, final boolean strict) {
|
||||
this.source = source;
|
||||
this.context = context;
|
||||
this.errors = errors;
|
||||
this.strict = strict;
|
||||
this.namespace = new Namespace(context.getNamespace());
|
||||
this.compileUnits = new HashSet<>();
|
||||
this.constantData = new ConstantData();
|
||||
this.state = EnumSet.of(State.INITIALIZED);
|
||||
this.dumpClass = context._compile_only && context._dest_dir != null;
|
||||
}
|
||||
|
||||
private String scriptsPackageName() {
|
||||
return dumpClass ? "" : (SCRIPTS_PACKAGE + '/');
|
||||
}
|
||||
|
||||
private int nextCompileUnitIndex() {
|
||||
return compileUnits.size() + 1;
|
||||
}
|
||||
|
||||
private String firstCompileUnitName() {
|
||||
return scriptsPackageName() + scriptName;
|
||||
}
|
||||
|
||||
private String nextCompileUnitName() {
|
||||
return firstCompileUnitName() + '$' + nextCompileUnitIndex();
|
||||
}
|
||||
|
||||
private CompileUnit addCompileUnit(final long initialWeight) {
|
||||
return addCompileUnit(nextCompileUnitName(), initialWeight);
|
||||
}
|
||||
|
||||
private CompileUnit addCompileUnit(final String unitClassName, final long initialWeight) {
|
||||
final CompileUnit compileUnit = initCompileUnit(unitClassName, initialWeight);
|
||||
compileUnits.add(compileUnit);
|
||||
LOG.info("Added compile unit " + compileUnit);
|
||||
return compileUnit;
|
||||
}
|
||||
|
||||
private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) {
|
||||
final ClassEmitter classEmitter = new ClassEmitter(this, unitClassName, strict);
|
||||
final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight);
|
||||
|
||||
classEmitter.begin();
|
||||
|
||||
final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE));
|
||||
initMethod.begin();
|
||||
initMethod.load(Type.OBJECT, 0);
|
||||
initMethod.newInstance(jdk.nashorn.internal.scripts.JS$.class);
|
||||
initMethod.returnVoid();
|
||||
initMethod.end();
|
||||
|
||||
return compileUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform compilation
|
||||
*
|
||||
* @return true if successful, false otherwise - if false check the error manager
|
||||
*/
|
||||
public boolean compile() {
|
||||
assert state.contains(State.INITIALIZED);
|
||||
|
||||
/** do we need to parse source? */
|
||||
if (!state.contains(State.PARSED)) {
|
||||
assert this.functionNode == null;
|
||||
this.functionNode = new Parser(this, strict).parse(RUN_SCRIPT.tag());
|
||||
|
||||
state.add(State.PARSED);
|
||||
debugPrintParse();
|
||||
|
||||
if (errors.hasErrors() || context._parse_only) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert !isLazy;
|
||||
//tag lazy nodes for later code generation and trampolines
|
||||
functionNode.accept(new NodeVisitor() {
|
||||
@Override
|
||||
public Node enter(final FunctionNode node) {
|
||||
if (LAZY_JIT) {
|
||||
node.setIsLazy(!node.isScript());
|
||||
}
|
||||
return node;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
assert isLazy;
|
||||
functionNode.accept(new NodeVisitor() {
|
||||
@Override
|
||||
public Node enter(final FunctionNode node) {
|
||||
node.setIsLazy(false);
|
||||
return null; //TODO do we want to do this recursively? then return "node" instead
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
assert functionNode != null;
|
||||
final boolean oldStrict = strict;
|
||||
|
||||
try {
|
||||
strict |= functionNode.isStrictMode();
|
||||
|
||||
if (!state.contains(State.LOWERED)) {
|
||||
debugPrintAST();
|
||||
functionNode.accept(new Lower(this));
|
||||
state.add(State.LOWERED);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
scriptName = computeNames();
|
||||
|
||||
// Main script code always goes to this compile unit. Note that since we start this with zero weight
|
||||
// and add script code last this class may end up slightly larger than others, but reserving one class
|
||||
// just for the main script seems wasteful.
|
||||
final CompileUnit scriptCompileUnit = addCompileUnit(firstCompileUnitName(), 0l);
|
||||
new Splitter(this, functionNode, scriptCompileUnit).split();
|
||||
assert functionNode.getCompileUnit() == scriptCompileUnit;
|
||||
|
||||
/** Compute compile units */
|
||||
assert strict == functionNode.isStrictMode() : "strict == " + strict + " but functionNode == " + functionNode.isStrictMode();
|
||||
if (functionNode.isStrictMode()) {
|
||||
strict = true;
|
||||
}
|
||||
|
||||
try {
|
||||
final CodeGenerator codegen = new CodeGenerator(this);
|
||||
functionNode.accept(codegen);
|
||||
codegen.generateScopeCalls();
|
||||
debugPrintAST();
|
||||
debugPrintParse();
|
||||
} catch (final VerifyError e) {
|
||||
if (context._verify_code || context._print_code) {
|
||||
context.getErr().println(e.getClass().getSimpleName() + ": " + e.getMessage());
|
||||
if (context._dump_on_error) {
|
||||
e.printStackTrace(context.getErr());
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
state.add(State.EMITTED);
|
||||
|
||||
code = new TreeMap<>();
|
||||
for (final CompileUnit compileUnit : compileUnits) {
|
||||
final ClassEmitter classEmitter = compileUnit.getClassEmitter();
|
||||
classEmitter.end();
|
||||
|
||||
if (!errors.hasErrors()) {
|
||||
final byte[] bytecode = classEmitter.toByteArray();
|
||||
if (bytecode != null) {
|
||||
code.put(compileUnit.getUnitClassName(), bytecode);
|
||||
debugDisassemble();
|
||||
debugVerify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (code.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
dumpClassFiles();
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
strict = oldStrict;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install compiled classes into a given loader
|
||||
* @param installer that takes the generated classes and puts them in the system
|
||||
* @return root script class - if there are several compile units they will also be installed
|
||||
*/
|
||||
public Class<?> install(final CodeInstaller installer) {
|
||||
assert state.contains(State.EMITTED);
|
||||
assert scriptName != null;
|
||||
|
||||
Class<?> rootClass = null;
|
||||
|
||||
for (final Entry<String, byte[]> entry : code.entrySet()) {
|
||||
final String className = entry.getKey();
|
||||
LOG.info("Installing class " + className);
|
||||
|
||||
final byte[] bytecode = entry.getValue();
|
||||
final Class<?> clazz = installer.install(Compiler.binaryName(className), bytecode);
|
||||
|
||||
if (rootClass == null && firstCompileUnitName().equals(className)) {
|
||||
rootClass = clazz;
|
||||
}
|
||||
|
||||
try {
|
||||
//use reflection to write source and constants table to installed classes
|
||||
clazz.getField(SOURCE.tag()).set(null, source);
|
||||
clazz.getField(CONSTANTS.tag()).set(null, constantData.toArray());
|
||||
} catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
LOG.info("Root class: " + rootClass);
|
||||
|
||||
return rootClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a unit that will hold a node of the specified weight.
|
||||
*
|
||||
* @param weight Weight of a node
|
||||
* @return Unit to hold node.
|
||||
*/
|
||||
CompileUnit findUnit(final long weight) {
|
||||
for (final CompileUnit unit : compileUnits) {
|
||||
if (unit.canHold(weight)) {
|
||||
unit.addWeight(weight);
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
|
||||
return addCompileUnit(weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a uniqueName name. Public as {@link Parser} is using this to
|
||||
* create symbols in a different package
|
||||
*
|
||||
* @param name to base unique name on
|
||||
* @return unique name
|
||||
*/
|
||||
public String uniqueName(final String name) {
|
||||
return namespace.uniqueName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to compute reserved names and base names for class to
|
||||
* be generated
|
||||
*
|
||||
* @return scriptName
|
||||
*/
|
||||
private String computeNames() {
|
||||
// Reserve internally used names.
|
||||
addReservedNames();
|
||||
|
||||
if (dumpClass) {
|
||||
// get source file name and remove ".js"
|
||||
final String baseName = getSource().getName();
|
||||
final int index = baseName.lastIndexOf(".js");
|
||||
if (index != -1) {
|
||||
return baseName.substring(0, index);
|
||||
}
|
||||
return baseName;
|
||||
}
|
||||
|
||||
return namespace.getParent().uniqueName(
|
||||
DEFAULT_SCRIPT_NAME.tag() +
|
||||
'$' +
|
||||
safeSourceName(source) +
|
||||
(isLazy ? CompilerConstants.LAZY.tag() : "")
|
||||
);
|
||||
}
|
||||
|
||||
private static String safeSourceName(final Source source) {
|
||||
String baseName = new File(source.getName()).getName();
|
||||
final int index = baseName.lastIndexOf(".js");
|
||||
if (index != -1) {
|
||||
baseName = baseName.substring(0, index);
|
||||
}
|
||||
|
||||
baseName = baseName.replace('.', '_').replace('-', '_');
|
||||
final String mangled = Mangler.mangle(baseName);
|
||||
|
||||
baseName = mangled != null ? mangled : baseName;
|
||||
return baseName;
|
||||
}
|
||||
|
||||
static void verify(final Context context, final byte[] code) {
|
||||
context.verify(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in the namespace with internally reserved names.
|
||||
*/
|
||||
private void addReservedNames() {
|
||||
namespace.uniqueName(SCOPE.tag());
|
||||
namespace.uniqueName(THIS.tag());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the constant data for this Compiler
|
||||
*
|
||||
* @return the constant data
|
||||
*/
|
||||
public ConstantData getConstantData() {
|
||||
return constantData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Context used for Compilation
|
||||
* @see Context
|
||||
* @return the context
|
||||
*/
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Source being compiled
|
||||
* @see Source
|
||||
* @return the source
|
||||
*/
|
||||
public Source getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error manager used for this compiler
|
||||
* @return the error manager
|
||||
*/
|
||||
public ErrorManager getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the namespace used for this Compiler
|
||||
* @see Namespace
|
||||
* @return the namespace
|
||||
*/
|
||||
public Namespace getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugging
|
||||
*/
|
||||
|
||||
/**
|
||||
* Print the AST before or after lowering, see --print-ast, --print-lower-ast
|
||||
*/
|
||||
private void debugPrintAST() {
|
||||
assert functionNode != null;
|
||||
if (context._print_lower_ast && state.contains(State.LOWERED) ||
|
||||
context._print_ast && !state.contains(State.LOWERED)) {
|
||||
context.getErr().println(new ASTWriter(functionNode));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the parsed code before or after lowering, see --print-parse, --print-lower-parse
|
||||
*/
|
||||
private boolean debugPrintParse() {
|
||||
if (errors.hasErrors()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert functionNode != null;
|
||||
|
||||
if (context._print_lower_parse && state.contains(State.LOWERED) ||
|
||||
context._print_parse && !state.contains(State.LOWERED)) {
|
||||
final PrintVisitor pv = new PrintVisitor();
|
||||
functionNode.accept(pv);
|
||||
context.getErr().print(pv);
|
||||
context.getErr().flush();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void debugDisassemble() {
|
||||
assert code != null;
|
||||
if (context._print_code) {
|
||||
for (final Map.Entry<String, byte[]> entry : code.entrySet()) {
|
||||
context.getErr().println("CLASS: " + entry.getKey());
|
||||
context.getErr().println();
|
||||
ClassEmitter.disassemble(context, entry.getValue());
|
||||
context.getErr().println("======");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void debugVerify() {
|
||||
if (context._verify_code) {
|
||||
for (final Map.Entry<String, byte[]> entry : code.entrySet()) {
|
||||
Compiler.verify(context, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the "-d" option - dump class files from script to specified output directory
|
||||
*
|
||||
* @throws IOException if classes cannot be written
|
||||
*/
|
||||
private void dumpClassFiles() throws IOException {
|
||||
if (context._dest_dir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert code != null;
|
||||
|
||||
for (final Entry<String, byte[]> entry : code.entrySet()) {
|
||||
final String className = entry.getKey();
|
||||
final String fileName = className.replace('.', File.separatorChar) + ".class";
|
||||
final int index = fileName.lastIndexOf(File.separatorChar);
|
||||
|
||||
if (index != -1) {
|
||||
final File dir = new File(fileName.substring(0, index));
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
throw new IOException(ECMAErrors.getMessage("io.error.cant.write", dir.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
final byte[] bytecode = entry.getValue();
|
||||
final File outFile = new File(context._dest_dir, fileName);
|
||||
try (final FileOutputStream fos = new FileOutputStream(outFile)) {
|
||||
fos.write(bytecode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a package/class name to a binary name.
|
||||
*
|
||||
* @param name Package/class name.
|
||||
* @return Binary name.
|
||||
*/
|
||||
public static String binaryName(final String name) {
|
||||
return name.replace('/', '.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a binary name to a package/class name.
|
||||
*
|
||||
* @param name Binary name.
|
||||
* @return Package/class name.
|
||||
*/
|
||||
public static String pathName(final String name) {
|
||||
return name.replace('.', '/');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
687
nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java
Normal file
687
nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java
Normal file
@ -0,0 +1,687 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* This class represents constant names of variables, methods and fields in
|
||||
* the compiler
|
||||
*/
|
||||
|
||||
public enum CompilerConstants {
|
||||
/** the __FILE__ variable */
|
||||
__FILE__,
|
||||
|
||||
/** the __DIR__ variable */
|
||||
__DIR__,
|
||||
|
||||
/** the __LINE__ variable */
|
||||
__LINE__,
|
||||
|
||||
/** lazy prefix for classes of jitted methods */
|
||||
LAZY("Lazy"),
|
||||
|
||||
/** leaf tag used for functions that require no scope */
|
||||
LEAF("__leaf__"),
|
||||
|
||||
/** constructor name */
|
||||
INIT("<init>"),
|
||||
|
||||
/** static initializer name */
|
||||
CLINIT("<clinit>"),
|
||||
|
||||
/** eval name */
|
||||
EVAL("eval"),
|
||||
|
||||
/** source name and class */
|
||||
SOURCE("source", Source.class),
|
||||
|
||||
/** constants name and class */
|
||||
CONSTANTS("constants", Object[].class),
|
||||
|
||||
/** strict mode field name and type */
|
||||
STRICT_MODE("strictMode", boolean.class),
|
||||
|
||||
/** default script name */
|
||||
DEFAULT_SCRIPT_NAME("Script"),
|
||||
|
||||
/** function prefix for anonymous functions */
|
||||
FUNCTION_PREFIX("function$"),
|
||||
|
||||
/** method name for Java method that is script entry point */
|
||||
RUN_SCRIPT("runScript"),
|
||||
|
||||
/** this name and slot */
|
||||
THIS("this", 0),
|
||||
|
||||
/** this debugger symbol */
|
||||
THIS_DEBUGGER("__this__"),
|
||||
|
||||
/** scope name, type and slot */
|
||||
SCOPE("__scope__", ScriptObject.class, 2),
|
||||
|
||||
/** the return value variable name were intermediate results are stored for scripts */
|
||||
SCRIPT_RETURN("__return__"),
|
||||
|
||||
/** the callee value variable when necessary */
|
||||
CALLEE("__callee__", ScriptFunction.class, 1),
|
||||
|
||||
/** the varargs variable when necessary */
|
||||
VARARGS("__varargs__"),
|
||||
|
||||
/** the arguments vector when necessary and the slot */
|
||||
ARGUMENTS("arguments", Object.class, 2),
|
||||
|
||||
/** prefix for iterators for for (x in ...) */
|
||||
ITERATOR_PREFIX("$iter"),
|
||||
|
||||
/** prefix for tag variable used for switch evaluation */
|
||||
SWITCH_TAG_PREFIX("$tag"),
|
||||
|
||||
/** prefix for all exceptions */
|
||||
EXCEPTION_PREFIX("$exception"),
|
||||
|
||||
/** prefix for quick slots generated in Store */
|
||||
QUICK_PREFIX("$quick"),
|
||||
|
||||
/** prefix for temporary variables */
|
||||
TEMP_PREFIX("$temp"),
|
||||
|
||||
/** prefix for literals */
|
||||
LITERAL_PREFIX("$lit"),
|
||||
|
||||
/** prefix for map */
|
||||
MAP("$map", 1),
|
||||
|
||||
/** prefix for regexps */
|
||||
REGEX_PREFIX("$regex"),
|
||||
|
||||
/** init scope */
|
||||
INIT_SCOPE("$scope", 2),
|
||||
|
||||
/** init arguments */
|
||||
INIT_ARGUMENTS("$arguments", 3),
|
||||
|
||||
/** prefix for all ScriptObject subclasses with fields, @see ObjectGenerator */
|
||||
JS_OBJECT_PREFIX("JO$"),
|
||||
|
||||
/** name for allocate method in JO$ objects */
|
||||
ALLOCATE("allocate"),
|
||||
|
||||
/** prefix for split methods, @see Splitter */
|
||||
SPLIT_PREFIX("$split"),
|
||||
|
||||
/** prefix for split array method and slot */
|
||||
SPLIT_ARRAY_ARG("split_array", 3),
|
||||
|
||||
/** get string from constant pool */
|
||||
GET_STRING("$getString"),
|
||||
|
||||
/** get map */
|
||||
GET_MAP("$getMap"),
|
||||
|
||||
/** get map */
|
||||
SET_MAP("$setMap"),
|
||||
|
||||
/** get array prefix */
|
||||
GET_ARRAY_PREFIX("$get"),
|
||||
|
||||
/** get array suffix */
|
||||
GET_ARRAY_SUFFIX("$array");
|
||||
|
||||
private final String tag;
|
||||
private final Class<?> type;
|
||||
private final int slot;
|
||||
|
||||
private CompilerConstants() {
|
||||
this.tag = name();
|
||||
this.type = null;
|
||||
this.slot = -1;
|
||||
}
|
||||
|
||||
private CompilerConstants(final String tag) {
|
||||
this(tag, -1);
|
||||
}
|
||||
|
||||
private CompilerConstants(final String tag, final int slot) {
|
||||
this(tag, null, slot);
|
||||
}
|
||||
|
||||
private CompilerConstants(final String tag, final Class<?> type) {
|
||||
this(tag, type, -1);
|
||||
}
|
||||
|
||||
private CompilerConstants(final String tag, final Class<?> type, final int slot) {
|
||||
this.tag = tag;
|
||||
this.type = type;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tag for this compile constant. Deliberately avoiding "name" here
|
||||
* not to conflate with enum implementation. This is the master string for the
|
||||
* constant - every constant has one.
|
||||
*
|
||||
* @return the tag
|
||||
*/
|
||||
public final String tag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for this compile constant
|
||||
*
|
||||
* @return type for this constant's instances, or null if N/A
|
||||
*/
|
||||
public final Class<?> type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the slot for this compile constant
|
||||
*
|
||||
* @return byte code slot where constant is stored or -1 if N/A
|
||||
*/
|
||||
public final int slot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a descriptor for this compile constant. Only relevant if it has
|
||||
* a type
|
||||
*
|
||||
* @return descriptor the descriptor
|
||||
*/
|
||||
public final String descriptor() {
|
||||
assert type != null : " asking for descriptor of typeless constant";
|
||||
return typeDescriptor(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal class name for a type
|
||||
*
|
||||
* @param type a type
|
||||
* @return the internal name for this type
|
||||
*/
|
||||
public static String className(final Class<?> type) {
|
||||
return Type.getInternalName(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the method descriptor for a given method type collection
|
||||
*
|
||||
* @param rtype return type
|
||||
* @param ptypes parameter types
|
||||
*
|
||||
* @return internal descriptor for this method
|
||||
*/
|
||||
public static String methodDescriptor(final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return Type.getMethodDescriptor(rtype, ptypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type descriptor for a type
|
||||
*
|
||||
* @param clazz a type
|
||||
*
|
||||
* @return the internal descriptor for this type
|
||||
*/
|
||||
public static String typeDescriptor(final Class<?> clazz) {
|
||||
return Type.getDescriptor(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing a void constructor for a given type. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param clazz the class
|
||||
*
|
||||
* @return Call representing void constructor for type
|
||||
*/
|
||||
public static Call constructorNoLookup(final Class<?> clazz) {
|
||||
return specialCallNoLookup(clazz, INIT.tag(), void.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing a constructor for a given type. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param className the type class name
|
||||
* @param ptypes the parameter types for the constructor
|
||||
*
|
||||
* @return Call representing constructor for type
|
||||
*/
|
||||
public static Call constructorNoLookup(final String className, final Class<?>... ptypes) {
|
||||
return specialCallNoLookup(className, INIT.tag(), methodDescriptor(void.class, ptypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing a constructor for a given type. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param clazz the class name
|
||||
* @param ptypes the parameter types for the constructor
|
||||
*
|
||||
* @return Call representing constructor for type
|
||||
*/
|
||||
public static Call constructorNoLookup(final Class<?> clazz, final Class<?>... ptypes) {
|
||||
return specialCallNoLookup(clazz, INIT.tag(), void.class, ptypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing an invokespecial to a given method. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param className the class name
|
||||
* @param name the method name
|
||||
* @param desc the descriptor
|
||||
*
|
||||
* @return Call representing specified invokespecial call
|
||||
*/
|
||||
public static Call specialCallNoLookup(final String className, final String name, final String desc) {
|
||||
return new Call(null, className, name, desc) {
|
||||
@Override
|
||||
public MethodEmitter invoke(final MethodEmitter method) {
|
||||
return method.invokeSpecial(className, name, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing an invokespecial to a given method. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param clazz the class
|
||||
* @param name the method name
|
||||
* @param rtype the return type
|
||||
* @param ptypes the parameter types
|
||||
*
|
||||
* @return Call representing specified invokespecial call
|
||||
*/
|
||||
public static Call specialCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return specialCallNoLookup(className(clazz), name, methodDescriptor(rtype, ptypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing an invokestatic to a given method. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param className the class name
|
||||
* @param name the method name
|
||||
* @param desc the descriptor
|
||||
*
|
||||
* @return Call representing specified invokestatic call
|
||||
*/
|
||||
public static Call staticCallNoLookup(final String className, final String name, final String desc) {
|
||||
return new Call(null, className, name, desc) {
|
||||
@Override
|
||||
public MethodEmitter invoke(final MethodEmitter method) {
|
||||
return method.invokeStatic(className, name, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing an invokestatic to a given method. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param clazz the class
|
||||
* @param name the method name
|
||||
* @param rtype the return type
|
||||
* @param ptypes the parameter types
|
||||
*
|
||||
* @return Call representing specified invokestatic call
|
||||
*/
|
||||
public static Call staticCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return staticCallNoLookup(className(clazz), name, methodDescriptor(rtype, ptypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing an invokevirtual to a given method. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param clazz the class
|
||||
* @param name the method name
|
||||
* @param rtype the return type
|
||||
* @param ptypes the parameter types
|
||||
*
|
||||
* @return Call representing specified invokevirtual call
|
||||
*/
|
||||
public static Call virtualCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) {
|
||||
@Override
|
||||
public MethodEmitter invoke(final MethodEmitter method) {
|
||||
return method.invokeVirtual(className, name, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a call representing an invokeinterface to a given method. Don't
|
||||
* attempt to look this up at compile time
|
||||
*
|
||||
* @param clazz the class
|
||||
* @param name the method name
|
||||
* @param rtype the return type
|
||||
* @param ptypes the parameter types
|
||||
*
|
||||
* @return Call representing specified invokeinterface call
|
||||
*/
|
||||
public static Call interfaceCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) {
|
||||
@Override
|
||||
public MethodEmitter invoke(final MethodEmitter method) {
|
||||
return method.invokeInterface(className, name, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a FieldAccess representing a virtual field, that can be subject to put
|
||||
* or get operations
|
||||
*
|
||||
* @param className name of the class where the field is a member
|
||||
* @param name name of the field
|
||||
* @param desc type descriptor of the field
|
||||
*
|
||||
* @return a field access object giving access code generation method for the virtual field
|
||||
*/
|
||||
public static FieldAccess virtualField(final String className, final String name, final String desc) {
|
||||
return new FieldAccess(className, name, desc) {
|
||||
@Override
|
||||
public MethodEmitter get(final MethodEmitter method) {
|
||||
return method.getField(className, name, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final MethodEmitter method) {
|
||||
method.putField(className, name, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a FieldAccess representing a virtual field, that can be subject to put
|
||||
* or get operations
|
||||
*
|
||||
* @param clazz class where the field is a member
|
||||
* @param name name of the field
|
||||
* @param type type of the field
|
||||
*
|
||||
* @return a field access object giving access code generation method for the virtual field
|
||||
*/
|
||||
public static FieldAccess virtualField(final Class<?> clazz, final String name, final Class<?> type) {
|
||||
return virtualField(className(clazz), name, typeDescriptor(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a FieldAccess representing a static field, that can be subject to put
|
||||
* or get operations
|
||||
*
|
||||
* @param className name of the class where the field is a member
|
||||
* @param name name of the field
|
||||
* @param desc type descriptor of the field
|
||||
*
|
||||
* @return a field access object giving access code generation method for the static field
|
||||
*/
|
||||
public static FieldAccess staticField(final String className, final String name, final String desc) {
|
||||
return new FieldAccess(className, name, desc) {
|
||||
@Override
|
||||
public MethodEmitter get(final MethodEmitter method) {
|
||||
return method.getStatic(className, name, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(final MethodEmitter method) {
|
||||
method.putStatic(className, name, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a FieldAccess representing a static field, that can be subject to put
|
||||
* or get operations
|
||||
*
|
||||
* @param clazz class where the field is a member
|
||||
* @param name name of the field
|
||||
* @param type type of the field
|
||||
*
|
||||
* @return a field access object giving access code generation method for the virtual field
|
||||
*/
|
||||
public static FieldAccess staticField(final Class<?> clazz, final String name, final Class<?> type) {
|
||||
return staticField(className(clazz), name, typeDescriptor(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a static call, looking up the method handle for it at the same time
|
||||
*
|
||||
* @param clazz the class
|
||||
* @param name the name of the method
|
||||
* @param rtype the return type of the method
|
||||
* @param ptypes the parameter types of the method
|
||||
*
|
||||
* @return the call object representing the static call
|
||||
*/
|
||||
public static Call staticCall(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return staticCall(MethodHandles.publicLookup(), clazz, name, rtype, ptypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a static call, given an explicit lookup, looking up the method handle for it at the same time
|
||||
*
|
||||
* @param lookup the lookup
|
||||
* @param clazz the class
|
||||
* @param name the name of the method
|
||||
* @param rtype the return type
|
||||
* @param ptypes the parameter types
|
||||
*
|
||||
* @return the call object representing the static call
|
||||
*/
|
||||
public static Call staticCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return new Call(MH.findStatic(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) {
|
||||
@Override
|
||||
public MethodEmitter invoke(final MethodEmitter method) {
|
||||
return method.invokeStatic(className, name, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a virtual call, looking up the method handle for it at the same time
|
||||
*
|
||||
* @param clazz the class
|
||||
* @param name the name of the method
|
||||
* @param rtype the return type of the method
|
||||
* @param ptypes the parameter types of the method
|
||||
*
|
||||
* @return the call object representing the virtual call
|
||||
*/
|
||||
public static Call virtualCall(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return virtualCall(MethodHandles.publicLookup(), clazz, name, rtype, ptypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a virtual call, given an explicit lookup, looking up the method handle for it at the same time
|
||||
*
|
||||
* @param lookup the lookup
|
||||
* @param clazz the class
|
||||
* @param name the name of the method
|
||||
* @param rtype the return type
|
||||
* @param ptypes the parameter types
|
||||
*
|
||||
* @return the call object representing the virtual call
|
||||
*/
|
||||
public static Call virtualCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
|
||||
return new Call(MH.findVirtual(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) {
|
||||
@Override
|
||||
public MethodEmitter invoke(final MethodEmitter method) {
|
||||
return method.invokeVirtual(className, name, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Private class representing an access. This can generate code into a method code or
|
||||
* a field access.
|
||||
*/
|
||||
private abstract static class Access {
|
||||
protected final MethodHandle methodHandle;
|
||||
protected final String className;
|
||||
protected final String name;
|
||||
protected final String descriptor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param methodHandle methodHandle or null if none
|
||||
* @param className class name for access
|
||||
* @param name field or method name for access
|
||||
* @param descriptor descriptor for access field or method
|
||||
*/
|
||||
protected Access(final MethodHandle methodHandle, final String className, final String name, final String descriptor) {
|
||||
this.methodHandle = methodHandle;
|
||||
this.className = className;
|
||||
this.name = name;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the method handle, or null if access hasn't been looked up
|
||||
*
|
||||
* @return method handle
|
||||
*/
|
||||
public MethodHandle methodHandle() {
|
||||
return methodHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class name of the access
|
||||
*
|
||||
* @return the class name
|
||||
*/
|
||||
public String className() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field name or method name of the access
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the descriptor of the method or field of the access
|
||||
*
|
||||
* @return the descriptor
|
||||
*/
|
||||
public String descriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Field access - this can be used for generating code for static or
|
||||
* virtual field accesses
|
||||
*/
|
||||
public abstract static class FieldAccess extends Access {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param className name of the class where the field is
|
||||
* @param name name of the field
|
||||
* @param descriptor descriptor of the field
|
||||
*/
|
||||
protected FieldAccess(final String className, final String name, final String descriptor) {
|
||||
super(null, className, name, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate get code for the field
|
||||
*
|
||||
* @param emitter a method emitter
|
||||
*
|
||||
* @return the method emitter
|
||||
*/
|
||||
protected abstract MethodEmitter get(final MethodEmitter emitter);
|
||||
|
||||
/**
|
||||
* Generate put code for the field
|
||||
*
|
||||
* @param emitter a method emitter
|
||||
*/
|
||||
protected abstract void put(final MethodEmitter emitter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call - this can be used for generating code for different types of calls
|
||||
*/
|
||||
public abstract static class Call extends Access {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param className class name for the method of the call
|
||||
* @param name method name
|
||||
* @param descriptor method descriptor
|
||||
*/
|
||||
protected Call(final String className, final String name, final String descriptor) {
|
||||
super(null, className, name, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param methodHandle method handle for the call if resolved
|
||||
* @param className class name for the method of the call
|
||||
* @param name method name
|
||||
* @param descriptor method descriptor
|
||||
*/
|
||||
protected Call(final MethodHandle methodHandle, final String className, final String name, final String descriptor) {
|
||||
super(methodHandle, className, name, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate invocation code for the method
|
||||
*
|
||||
* @param emitter a method emitter
|
||||
*
|
||||
* @return the method emitter
|
||||
*/
|
||||
protected abstract MethodEmitter invoke(final MethodEmitter emitter);
|
||||
}
|
||||
|
||||
}
|
||||
165
nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java
Normal file
165
nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Manages constants needed by code generation. Objects are maintained in an
|
||||
* interning maps to remove duplicates.
|
||||
*/
|
||||
public class ConstantData {
|
||||
/** Constant table. */
|
||||
final List<Object> constants;
|
||||
|
||||
/** Constant table string interning map. */
|
||||
final Map<String, Integer> stringMap;
|
||||
|
||||
/** Constant table object interning map. */
|
||||
final Map<Object, Integer> objectMap;
|
||||
|
||||
private static class ArrayWrapper {
|
||||
private final Object array;
|
||||
private final int hashCode;
|
||||
|
||||
public ArrayWrapper(final Object array) {
|
||||
this.array = array;
|
||||
this.hashCode = calcHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a shallow hashcode for the array.
|
||||
* @return Hashcode with elements factored in.
|
||||
*/
|
||||
private int calcHashCode() {
|
||||
final Class<?> cls = array.getClass();
|
||||
|
||||
if (cls == Object[].class) {
|
||||
return Arrays.hashCode((Object[])array);
|
||||
} else if (cls == double[].class) {
|
||||
return Arrays.hashCode((double[])array);
|
||||
} if (cls == long[].class) {
|
||||
return Arrays.hashCode((long[])array);
|
||||
} if (cls == int[].class) {
|
||||
return Arrays.hashCode((int[])array);
|
||||
}
|
||||
|
||||
throw new AssertionError("ConstantData doesn't support " + cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (!(other instanceof ArrayWrapper)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Object otherArray = ((ArrayWrapper)other).array;
|
||||
|
||||
if (array == otherArray) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Class<?> cls = array.getClass();
|
||||
|
||||
if (cls == otherArray.getClass()) {
|
||||
if (cls == Object[].class) {
|
||||
return Arrays.equals((Object[])array, (Object[])otherArray);
|
||||
} else if (cls == double[].class) {
|
||||
return Arrays.equals((double[])array, (double[])otherArray);
|
||||
} else if (cls == long[].class) {
|
||||
return Arrays.equals((long[])array, (long[])otherArray);
|
||||
} else if (cls == int[].class) {
|
||||
return Arrays.equals((int[])array, (int[])otherArray);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
ConstantData() {
|
||||
this.constants = new ArrayList<>();
|
||||
this.stringMap = new HashMap<>();
|
||||
this.objectMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a string to the constant data
|
||||
*
|
||||
* @param string the string to add
|
||||
* @return the index in the constant pool that the string was given
|
||||
*/
|
||||
public int add(final String string) {
|
||||
final Integer value = stringMap.get(string);
|
||||
|
||||
if (value != null) {
|
||||
return value.intValue();
|
||||
}
|
||||
|
||||
constants.add(string);
|
||||
final int index = constants.size() - 1;
|
||||
stringMap.put(string, index);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object to the constant data
|
||||
*
|
||||
* @param object the string to add
|
||||
* @return the index in the constant pool that the object was given
|
||||
*/
|
||||
public int add(final Object object) {
|
||||
final Object entry = object.getClass().isArray() ? new ArrayWrapper(object) : object;
|
||||
final Integer value = objectMap.get(entry);
|
||||
|
||||
if (value != null) {
|
||||
return value.intValue();
|
||||
}
|
||||
|
||||
constants.add(object);
|
||||
final int index = constants.size() - 1;
|
||||
objectMap.put(entry, index);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
Object[] toArray() {
|
||||
return constants.toArray();
|
||||
}
|
||||
}
|
||||
49
nashorn/src/jdk/nashorn/internal/codegen/Emitter.java
Normal file
49
nashorn/src/jdk/nashorn/internal/codegen/Emitter.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
/**
|
||||
* Interface for anything that interacts with a low level bytecode
|
||||
* generation module, for example ASM.
|
||||
* <p>
|
||||
* This is pretty generic, i.e. it can be a ClassEmitter, MethodEmitter
|
||||
* or potentially even more fine grained stuff.
|
||||
*
|
||||
*/
|
||||
public interface Emitter {
|
||||
|
||||
/**
|
||||
* Register the start of emission for this CodeEmitter
|
||||
*/
|
||||
public void begin();
|
||||
|
||||
/**
|
||||
* Register the end of emission for this CodeEmitter.
|
||||
* This is typically required before generated code can
|
||||
* be requested from it
|
||||
*/
|
||||
public void end();
|
||||
}
|
||||
196
nashorn/src/jdk/nashorn/internal/codegen/Frame.java
Normal file
196
nashorn/src/jdk/nashorn/internal/codegen/Frame.java
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
|
||||
/**
|
||||
* Tracks the variable area state.
|
||||
*
|
||||
*/
|
||||
public final class Frame {
|
||||
/** Previous frame. */
|
||||
private Frame previous;
|
||||
|
||||
/** Current variables. */
|
||||
private final ArrayList<Symbol> symbols;
|
||||
|
||||
/** Number of slots in previous frame. */
|
||||
private int baseCount;
|
||||
|
||||
/** Number of slots in this frame. */
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param previous frame, the parent variable frame
|
||||
*/
|
||||
public Frame(final Frame previous) {
|
||||
this.previous = previous;
|
||||
this.symbols = new ArrayList<>();
|
||||
this.baseCount = getBaseCount();
|
||||
this.count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
* @param frame
|
||||
* @param symbols
|
||||
*/
|
||||
private Frame(final Frame frame, final List<Symbol> symbols) {
|
||||
this.previous = frame.getPrevious() == null ? null : new Frame(frame.getPrevious(), frame.getPrevious().getSymbols());
|
||||
this.symbols = new ArrayList<>(frame.getSymbols());
|
||||
this.baseCount = frame.getBaseCount();
|
||||
this.count = frame.getCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the frame
|
||||
*
|
||||
* @return a new frame with the identical contents
|
||||
*/
|
||||
public Frame copy() {
|
||||
return new Frame(this, getSymbols());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new variable to the frame.
|
||||
* @param symbol Symbol representing variable.
|
||||
*/
|
||||
public void addSymbol(final Symbol symbol) {
|
||||
final int slot = symbol.getSlot();
|
||||
if (slot < 0) {
|
||||
symbols.add(symbol);
|
||||
count += symbol.slotCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Realign slot numbering prior to code generation.
|
||||
* @return Number of slots in frame.
|
||||
*/
|
||||
public int realign() {
|
||||
baseCount = getBaseCount();
|
||||
count = 0;
|
||||
|
||||
for (final Symbol symbol : symbols) {
|
||||
if (symbol.hasSlot()) {
|
||||
symbol.setSlot(baseCount + count);
|
||||
count += symbol.slotCount();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the slot count of previous frames.
|
||||
* @return Number of slots in previous frames.
|
||||
*/
|
||||
private int getBaseCount() {
|
||||
return previous != null ? previous.getSlotCount() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the number of slots to top of frame.
|
||||
* @return Number of slots in total.
|
||||
*/
|
||||
public int getSlotCount() {
|
||||
return baseCount + count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
Frame f = this;
|
||||
boolean hasPrev = false;
|
||||
int pos = 0;
|
||||
|
||||
do {
|
||||
if (hasPrev) {
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
sb.append("#").
|
||||
append(pos++).
|
||||
append(" {baseCount:").
|
||||
append(baseCount).
|
||||
append(", ").
|
||||
append("count:").
|
||||
append(count).
|
||||
append("} ");
|
||||
|
||||
for (final Symbol var : f.getSymbols()) {
|
||||
sb.append('[').
|
||||
append(var.toString()).
|
||||
append(' ').
|
||||
append(var.hashCode()).
|
||||
append("] ");
|
||||
}
|
||||
|
||||
f = f.getPrevious();
|
||||
hasPrev = true;
|
||||
} while (f != null);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get variable count for this frame
|
||||
* @return variable count
|
||||
*/
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get previous frame
|
||||
* @return previous frame
|
||||
*/
|
||||
public Frame getPrevious() {
|
||||
return previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set previous frame
|
||||
* @param previous previous frame
|
||||
*/
|
||||
public void setPrevious(final Frame previous) {
|
||||
this.previous = previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get symbols in frame
|
||||
* @return a list of symbols in this frame
|
||||
*/
|
||||
public List<Symbol> getSymbols() {
|
||||
return Collections.unmodifiableList(symbols);
|
||||
}
|
||||
}
|
||||
209
nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java
Normal file
209
nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
|
||||
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
|
||||
|
||||
/**
|
||||
* Class that generates function signatures for dynamic calls
|
||||
*/
|
||||
public final class FunctionSignature {
|
||||
|
||||
/** parameter types that ASM can understand */
|
||||
private final Type[] paramTypes;
|
||||
|
||||
/** return type that ASM can understand */
|
||||
private final Type returnType;
|
||||
|
||||
/** valid Java descriptor string for function */
|
||||
private final String descriptor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Create a FunctionSignature given arguments as AST Nodes
|
||||
*
|
||||
* @param hasSelf does the function have a self slot?
|
||||
* @param retType what is the return type
|
||||
* @param args argument list of AST Nodes
|
||||
*/
|
||||
public FunctionSignature(final boolean hasSelf, final Type retType, final List<? extends Node> args) {
|
||||
this(hasSelf, false, retType, FunctionSignature.typeArray(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Create a FunctionSignature given arguments as AST Nodes
|
||||
*
|
||||
* @param hasSelf does the function have a self slot?
|
||||
* @param hasCallee does the function need a callee variable
|
||||
* @param retType what is the return type
|
||||
* @param args argument list of AST Nodes
|
||||
*/
|
||||
public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List<? extends Node> args) {
|
||||
this(hasSelf, hasCallee, retType, FunctionSignature.typeArray(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Create a FunctionSignature given arguments as AST Nodes
|
||||
*
|
||||
* @param hasSelf does the function have a self slot?
|
||||
* @param retType what is the return type
|
||||
* @param nArgs number of arguments
|
||||
*/
|
||||
public FunctionSignature(final boolean hasSelf, final Type retType, final int nArgs) {
|
||||
this(hasSelf, false, retType, FunctionSignature.objectArgs(nArgs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Create a FunctionSignature given argument types only
|
||||
*
|
||||
* @param hasSelf does the function have a self slot?
|
||||
* @param hasCallee does the function have a callee slot?
|
||||
* @param retType what is the return type
|
||||
* @param argTypes argument list of AST Nodes
|
||||
*/
|
||||
public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final Type... argTypes) {
|
||||
final boolean isVarArg;
|
||||
|
||||
int count = 1;
|
||||
|
||||
if (argTypes == null) {
|
||||
isVarArg = true;
|
||||
} else {
|
||||
isVarArg = argTypes.length > LinkerCallSite.ARGLIMIT;
|
||||
count = isVarArg ? 1 : argTypes.length;
|
||||
}
|
||||
|
||||
int first = 0;
|
||||
|
||||
if (hasSelf) {
|
||||
count++;
|
||||
first++;
|
||||
}
|
||||
if (hasCallee) {
|
||||
count++;
|
||||
first++;
|
||||
}
|
||||
|
||||
paramTypes = new Type[count];
|
||||
|
||||
if (hasSelf) {
|
||||
paramTypes[THIS.slot()] = Type.OBJECT;
|
||||
}
|
||||
if (hasCallee) {
|
||||
paramTypes[CALLEE.slot()] = Type.typeFor(ScriptFunction.class);
|
||||
}
|
||||
|
||||
if (isVarArg) {
|
||||
paramTypes[first] = Type.OBJECT_ARRAY;
|
||||
} else if (argTypes != null) {
|
||||
for (int i = first, j = 0; i < count; i++, j++) {
|
||||
paramTypes[i] = argTypes[j];
|
||||
if (paramTypes[i].isObject()) {
|
||||
paramTypes[i] = Type.OBJECT; //TODO: for now, turn java/lang/String into java/lang/Object as we aren't as specific.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert false : "isVarArgs cannot be false when argTypes are null";
|
||||
}
|
||||
|
||||
returnType = retType;
|
||||
descriptor = Type.getMethodDescriptor(returnType, paramTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function that converts an array of nodes to their Types
|
||||
*
|
||||
* @param args node arg list
|
||||
*
|
||||
* @return the array of types
|
||||
*/
|
||||
private static Type[] typeArray(final List<? extends Node> args) {
|
||||
if (args == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Type[] typeArray = new Type[args.size()];
|
||||
|
||||
int pos = 0;
|
||||
for (final Node arg : args) {
|
||||
typeArray[pos++] = arg.getType();
|
||||
}
|
||||
|
||||
return typeArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of param types
|
||||
*/
|
||||
public int size() {
|
||||
return paramTypes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generic signature of the function being compiled.
|
||||
*
|
||||
* @param functionNode function being compiled.
|
||||
* @return function signature.
|
||||
*/
|
||||
public static String functionSignature(final FunctionNode functionNode) {
|
||||
return new FunctionSignature(
|
||||
true,
|
||||
functionNode.needsCallee(),
|
||||
functionNode.getReturnType(),
|
||||
(functionNode.isVarArg() && !functionNode.isScript()) ?
|
||||
null :
|
||||
functionNode.getParameters()).toString();
|
||||
}
|
||||
|
||||
private static Type[] objectArgs(final int nArgs) {
|
||||
final Type[] array = new Type[nArgs];
|
||||
for (int i = 0; i < nArgs; i++) {
|
||||
array[i] = Type.OBJECT;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
||||
3057
nashorn/src/jdk/nashorn/internal/codegen/Lower.java
Normal file
3057
nashorn/src/jdk/nashorn/internal/codegen/Lower.java
Normal file
File diff suppressed because it is too large
Load Diff
2349
nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
Normal file
2349
nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
Normal file
File diff suppressed because it is too large
Load Diff
101
nashorn/src/jdk/nashorn/internal/codegen/Namespace.java
Normal file
101
nashorn/src/jdk/nashorn/internal/codegen/Namespace.java
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A name space hierarchy, where each level holds a name directory with
|
||||
* names that may be unique for each level.
|
||||
*/
|
||||
|
||||
public class Namespace {
|
||||
/** Parent namespace. */
|
||||
private final Namespace parent;
|
||||
|
||||
/** Name directory - version count for each name */
|
||||
private final HashMap<String, Integer> directory;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Namespace() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param parent parent name space
|
||||
*/
|
||||
public Namespace(final Namespace parent) {
|
||||
this.parent = parent;
|
||||
directory = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent Namespace of this space.
|
||||
*
|
||||
* @return parent name space
|
||||
*/
|
||||
public Namespace getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private HashMap<String, Integer> getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a uniqueName name in the namespace in the form base$n where n varies
|
||||
* .
|
||||
* @param base Base of name. Base will be returned if uniqueName.
|
||||
*
|
||||
* @return Generated uniqueName name.
|
||||
*/
|
||||
public String uniqueName(final String base) {
|
||||
for (Namespace namespace = this; namespace != null; namespace = namespace.getParent()) {
|
||||
final HashMap<String, Integer> namespaceDirectory = namespace.getDirectory();
|
||||
final Integer counter = namespaceDirectory.get(base);
|
||||
|
||||
if (counter != null) {
|
||||
final int count = counter + 1;
|
||||
namespaceDirectory.put(base, count);
|
||||
|
||||
return base + "$" + count;
|
||||
}
|
||||
}
|
||||
|
||||
directory.put(base, 0);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return directory.toString();
|
||||
}
|
||||
}
|
||||
701
nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java
Normal file
701
nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java
Normal file
@ -0,0 +1,701 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
|
||||
import static jdk.nashorn.internal.codegen.types.Type.BOOLEAN;
|
||||
import static jdk.nashorn.internal.codegen.types.Type.INT;
|
||||
import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.MutableCallSite;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode.Request;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.linker.Lookup;
|
||||
import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
|
||||
|
||||
/**
|
||||
* Optimistic call site that assumes its Object arguments to be of a boxed type.
|
||||
* Gradually reverts to wider boxed types if the assumption for the RuntimeNode
|
||||
* is proven wrong. Finally reverts to the generic ScriptRuntime method.
|
||||
*
|
||||
* This is used from the CodeGenerator when we have a runtime node, but 1 or more
|
||||
* primitive arguments. This class generated appropriate specializations, for example
|
||||
* {@code Object a === int b} is a good idea to specialize to {@code ((Integer)a).intValue() == b}
|
||||
* surrounded by catch blocks that will try less narrow specializations
|
||||
*/
|
||||
public class RuntimeCallSite extends MutableCallSite {
|
||||
static final Call BOOTSTRAP = staticCallNoLookup(RuntimeCallSite.class, "bootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
|
||||
|
||||
private static final MethodHandle NEXT = findOwnMH("next", MethodHandle.class);
|
||||
|
||||
private final RuntimeNode.Request request;
|
||||
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* A specialized runtime node, i.e. on where we know at least one more specific type than object
|
||||
*/
|
||||
static final class SpecializedRuntimeNode {
|
||||
private static final char REQUEST_SEPARATOR = ':';
|
||||
|
||||
private final RuntimeNode.Request request;
|
||||
|
||||
private final Type[] parameterTypes;
|
||||
|
||||
private final Type returnType;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param request runtime node request to specialize
|
||||
* @param parameterTypes parameter types of the call site
|
||||
* @param returnType return type of the call site
|
||||
*/
|
||||
SpecializedRuntimeNode(final RuntimeNode.Request request, final Type[] parameterTypes, final Type returnType) {
|
||||
this.request = request;
|
||||
this.parameterTypes = parameterTypes;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The first type to try to use for this genrated runtime node
|
||||
*
|
||||
* @return a type
|
||||
*/
|
||||
public Type firstTypeGuess() {
|
||||
Type widest = Type.UNKNOWN;
|
||||
for (final Type type : parameterTypes) {
|
||||
if (type.isObject()) {
|
||||
continue;
|
||||
}
|
||||
widest = Type.widest(type, widest);
|
||||
}
|
||||
widest = Type.widest(widest, firstTypeGuessForObject(request));
|
||||
|
||||
return widest;
|
||||
}
|
||||
|
||||
private static Type firstTypeGuessForObject(final Request request) {
|
||||
switch (request) {
|
||||
case ADD:
|
||||
return INT;
|
||||
default:
|
||||
return BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
Request getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
Type[] getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
Type getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
private static char descFor(final Type type) {
|
||||
if (type.isObject()) {
|
||||
return 'O';
|
||||
}
|
||||
return type.getDescriptor().charAt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other instanceof SpecializedRuntimeNode) {
|
||||
final SpecializedRuntimeNode otherNode = (SpecializedRuntimeNode)other;
|
||||
|
||||
if (!otherNode.getReturnType().equals(getReturnType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getParameterTypes().length != otherNode.getParameterTypes().length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < getParameterTypes().length; i++) {
|
||||
if (!Type.areEquivalent(getParameterTypes()[i], otherNode.getParameterTypes()[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return otherNode.getRequest().equals(getRequest());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getRequest().toString().hashCode();
|
||||
hashCode ^= getReturnType().hashCode();
|
||||
for (final Type type : getParameterTypes()) {
|
||||
hashCode ^= type.hashCode();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(getRequest().toString());
|
||||
sb.append(REQUEST_SEPARATOR);
|
||||
sb.append(descFor(getReturnType()));
|
||||
|
||||
for (final Type type : getParameterTypes()) {
|
||||
sb.append(descFor(type));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
String getName(final Type extraType) {
|
||||
return toString() + "_" + descFor(extraType);
|
||||
}
|
||||
|
||||
String getInitialName() {
|
||||
return getName(firstTypeGuess());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param type method type for call site
|
||||
* @param name name of runtime call
|
||||
*/
|
||||
RuntimeCallSite(final MethodType type, final String name) {
|
||||
super(type);
|
||||
this.name = name;
|
||||
this.request = Request.valueOf(name.substring(0, name.indexOf(SpecializedRuntimeNode.REQUEST_SEPARATOR)));
|
||||
setTarget(makeMethod(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrapper for a specialized Runtime call
|
||||
*
|
||||
* @param lookup lookup
|
||||
* @param initialName initial name for callsite
|
||||
* @param type method type for call site
|
||||
*
|
||||
* @return callsite for a runtime node
|
||||
*/
|
||||
public static CallSite bootstrap(final MethodHandles.Lookup lookup, final String initialName, final MethodType type) {
|
||||
return new RuntimeCallSite(type, initialName);
|
||||
}
|
||||
|
||||
private String nextName(final String requestName) {
|
||||
if (requestName.equals(request.toString())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final char[] c = requestName.toCharArray();
|
||||
final int last = c.length - 1;
|
||||
|
||||
if (c[last - 1] != '_') {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (c[last]) {
|
||||
case 'Z':
|
||||
c[last] = 'I';
|
||||
break;
|
||||
case 'I':
|
||||
c[last] = 'J';
|
||||
break;
|
||||
case 'J':
|
||||
c[last] = 'D';
|
||||
break;
|
||||
case 'D':
|
||||
default:
|
||||
return request.toString();
|
||||
}
|
||||
|
||||
return new String(c);
|
||||
}
|
||||
|
||||
private boolean isSpecialized(final String requestName) {
|
||||
return nextName(requestName) != null;
|
||||
}
|
||||
|
||||
private MethodHandle makeMethod(final String requestName) {
|
||||
MethodHandle mh;
|
||||
|
||||
if (isSpecialized(requestName)) {
|
||||
final Class<?> boxedType;
|
||||
final Class<?> primitiveType;
|
||||
|
||||
switch (requestName.charAt(requestName.length() - 1)) {
|
||||
case 'Z':
|
||||
boxedType = Boolean.class;
|
||||
primitiveType = int.class;
|
||||
break;
|
||||
case 'I':
|
||||
boxedType = Integer.class;
|
||||
primitiveType = int.class;
|
||||
break;
|
||||
case 'J':
|
||||
boxedType = Long.class;
|
||||
primitiveType = long.class;
|
||||
break;
|
||||
case 'D':
|
||||
boxedType = Number.class;
|
||||
primitiveType = double.class;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("should not reach here");
|
||||
}
|
||||
|
||||
final boolean isStrictCmp = (request == Request.EQ_STRICT || request == Request.NE_STRICT);
|
||||
|
||||
if (isStrictCmp &&
|
||||
(boxedType != Boolean.class &&
|
||||
(type().parameterType(0) == boolean.class ||
|
||||
type().parameterType(1) == boolean.class))) {
|
||||
// number and boolean are never strictly equal, e.g. 0 !== false
|
||||
mh = MH.dropArguments(MH.constant(boolean.class, request == Request.NE_STRICT), 0, type().parameterArray());
|
||||
} else {
|
||||
mh = METHODS.get(request.name().replace("_STRICT", "") + primitiveType.getSimpleName());
|
||||
// unbox objects
|
||||
|
||||
for (int i = 0; i < type().parameterCount(); i++) {
|
||||
if (!type().parameterType(i).isPrimitive()) {
|
||||
mh = MH.filterArguments(mh, i, UNBOX.get(boxedType));
|
||||
}
|
||||
}
|
||||
|
||||
mh = Lookup.filterReturnType(mh, type().returnType());
|
||||
mh = MH.explicitCastArguments(mh, type());
|
||||
}
|
||||
|
||||
final MethodHandle fallback = MH.foldArguments(MethodHandles.exactInvoker(type()), MH.bindTo(NEXT, this));
|
||||
|
||||
MethodHandle guard;
|
||||
if (type().parameterType(0).isPrimitive()) {
|
||||
guard = MH.insertArguments(
|
||||
MH.dropArguments(CHECKCAST, 1, type().parameterType(0)), 0, boxedType);
|
||||
} else if (type().parameterType(1).isPrimitive()) {
|
||||
guard = MH.insertArguments(
|
||||
MH.dropArguments(CHECKCAST, 2, type().parameterType(1)), 0, boxedType);
|
||||
} else {
|
||||
assert !type().parameterType(0).isPrimitive() && !type().parameterType(1).isPrimitive();
|
||||
guard = MH.insertArguments(CHECKCAST2, 0, boxedType);
|
||||
}
|
||||
|
||||
if (request == Request.ADD && boxedType == Integer.class) {
|
||||
// int add needs additional overflow check
|
||||
MethodHandle addcheck = ADDCHECK;
|
||||
for (int i = 0; i < type().parameterCount(); i++) {
|
||||
if (!type().parameterType(i).isPrimitive()) {
|
||||
addcheck = MH.filterArguments(addcheck, i, UNBOX.get(boxedType));
|
||||
}
|
||||
}
|
||||
addcheck = MH.explicitCastArguments(addcheck, type().changeReturnType(boolean.class));
|
||||
guard = MH.guardWithTest(guard, addcheck,
|
||||
MH.dropArguments(MH.constant(boolean.class, false), 0, type().parameterArray()));
|
||||
}
|
||||
|
||||
return MH.guardWithTest(guard, mh, fallback);
|
||||
}
|
||||
|
||||
// generic fallback
|
||||
return MH.explicitCastArguments(Lookup.filterReturnType(GENERIC_METHODS.get(request.name()), type().returnType()), type());
|
||||
}
|
||||
|
||||
/**
|
||||
* This is public just so that the generated specialization code can
|
||||
* use it to get the next wider typed method
|
||||
*
|
||||
* Do not call directly
|
||||
*
|
||||
* @return next wider specialization method for this RuntimeCallSite
|
||||
*/
|
||||
public MethodHandle next() {
|
||||
this.name = nextName(name);
|
||||
final MethodHandle next = makeMethod(name);
|
||||
setTarget(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " " + name;
|
||||
}
|
||||
|
||||
/** Method cache */
|
||||
private static final Map<String, MethodHandle> METHODS;
|
||||
|
||||
/** Generic method cache */
|
||||
private static final Map<String, MethodHandle> GENERIC_METHODS;
|
||||
|
||||
/** Unbox cache */
|
||||
private static final Map<Class<?>, MethodHandle> UNBOX;
|
||||
|
||||
private static final MethodHandle CHECKCAST = findOwnMH("checkcast", boolean.class, Class.class, Object.class);
|
||||
private static final MethodHandle CHECKCAST2 = findOwnMH("checkcast", boolean.class, Class.class, Object.class, Object.class);
|
||||
private static final MethodHandle ADDCHECK = findOwnMH("ADDcheck", boolean.class, int.class, int.class);
|
||||
|
||||
/**
|
||||
* Build maps of correct boxing operations
|
||||
*/
|
||||
static {
|
||||
UNBOX = new HashMap<>();
|
||||
UNBOX.put(Boolean.class, findOwnMH("unboxZ", int.class, Object.class));
|
||||
UNBOX.put(Integer.class, findOwnMH("unboxI", int.class, Object.class));
|
||||
UNBOX.put(Long.class, findOwnMH("unboxJ", long.class, Object.class));
|
||||
UNBOX.put(Number.class, findOwnMH("unboxD", double.class, Object.class));
|
||||
|
||||
METHODS = new HashMap<>();
|
||||
|
||||
for (final Request req : Request.values()) {
|
||||
if (req.canSpecialize()) {
|
||||
if (req.name().endsWith("_STRICT")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final boolean isCmp = Request.isComparison(req);
|
||||
|
||||
METHODS.put(req.name() + "int", findOwnMH(req.name(), (isCmp ? boolean.class : int.class), int.class, int.class));
|
||||
METHODS.put(req.name() + "long", findOwnMH(req.name(), (isCmp ? boolean.class : long.class), long.class, long.class));
|
||||
METHODS.put(req.name() + "double", findOwnMH(req.name(), (isCmp ? boolean.class : double.class), double.class, double.class));
|
||||
}
|
||||
}
|
||||
|
||||
GENERIC_METHODS = new HashMap<>();
|
||||
for (final Request req : Request.values()) {
|
||||
if (req.canSpecialize()) {
|
||||
GENERIC_METHODS.put(req.name(), MH.findStatic(MethodHandles.lookup(), ScriptRuntime.class, req.name(),
|
||||
MH.type(req.getReturnType().getTypeClass(), Object.class, Object.class)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of != operator for two int arguments. Do not call directly.
|
||||
* @param a int
|
||||
* @param b int
|
||||
* @return a != b
|
||||
*/
|
||||
public static boolean NE(final int a, final int b) {
|
||||
return a != b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of != operator for two double arguments. Do not call directly.
|
||||
* @param a double
|
||||
* @param b double
|
||||
* @return a != b
|
||||
*/
|
||||
public static boolean NE(final double a, final double b) {
|
||||
return a != b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of != operator for two long arguments. Do not call directly.
|
||||
* @param a long
|
||||
* @param b long
|
||||
* @return a != b
|
||||
*/
|
||||
public static boolean NE(final long a, final long b) {
|
||||
return a != b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of == operator for two int arguments. Do not call directly.
|
||||
* @param a int
|
||||
* @param b int
|
||||
* @return a == b
|
||||
*/
|
||||
public static boolean EQ(final int a, final int b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of == operator for two double arguments. Do not call directly.
|
||||
* @param a double
|
||||
* @param b double
|
||||
* @return a == b
|
||||
*/
|
||||
public static boolean EQ(final double a, final double b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of == operator for two long arguments. Do not call directly.
|
||||
* @param a long
|
||||
* @param b long
|
||||
* @return a == b
|
||||
*/
|
||||
public static boolean EQ(final long a, final long b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of < operator for two int arguments. Do not call directly.
|
||||
* @param a int
|
||||
* @param b int
|
||||
* @return a < b
|
||||
*/
|
||||
public static boolean LT(final int a, final int b) {
|
||||
return a < b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of < operator for two double arguments. Do not call directly.
|
||||
* @param a double
|
||||
* @param b double
|
||||
* @return a < b
|
||||
*/
|
||||
public static boolean LT(final double a, final double b) {
|
||||
return a < b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of < operator for two long arguments. Do not call directly.
|
||||
* @param a long
|
||||
* @param b long
|
||||
* @return a < b
|
||||
*/
|
||||
public static boolean LT(final long a, final long b) {
|
||||
return a < b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of <= operator for two int arguments. Do not call directly.
|
||||
* @param a int
|
||||
* @param b int
|
||||
* @return a <= b
|
||||
*/
|
||||
public static boolean LE(final int a, final int b) {
|
||||
return a <= b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of <= operator for two double arguments. Do not call directly.
|
||||
* @param a double
|
||||
* @param b double
|
||||
* @return a <= b
|
||||
*/
|
||||
public static boolean LE(final double a, final double b) {
|
||||
return a <= b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of <= operator for two long arguments. Do not call directly.
|
||||
* @param a long
|
||||
* @param b long
|
||||
* @return a <= b
|
||||
*/
|
||||
public static boolean LE(final long a, final long b) {
|
||||
return a <= b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of > operator for two int arguments. Do not call directly.
|
||||
* @param a int
|
||||
* @param b int
|
||||
* @return a > b
|
||||
*/
|
||||
public static boolean GT(final int a, final int b) {
|
||||
return a > b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of > operator for two double arguments. Do not call directly.
|
||||
* @param a double
|
||||
* @param b double
|
||||
* @return a > b
|
||||
*/
|
||||
public static boolean GT(final double a, final double b) {
|
||||
return a > b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of > operator for two long arguments. Do not call directly.
|
||||
* @param a long
|
||||
* @param b long
|
||||
* @return a > b
|
||||
*/
|
||||
public static boolean GT(final long a, final long b) {
|
||||
return a > b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of >= operator for two int arguments. Do not call directly.
|
||||
* @param a int
|
||||
* @param b int
|
||||
* @return a >= b
|
||||
*/
|
||||
public static boolean GE(final int a, final int b) {
|
||||
return a >= b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of >= operator for two double arguments. Do not call directly.
|
||||
* @param a double
|
||||
* @param b double
|
||||
* @return a >= b
|
||||
*/
|
||||
public static boolean GE(final double a, final double b) {
|
||||
return a >= b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of >= operator for two long arguments. Do not call directly.
|
||||
* @param a long
|
||||
* @param b long
|
||||
* @return a >= b
|
||||
*/
|
||||
public static boolean GE(final long a, final long b) {
|
||||
return a >= b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of + operator for two int arguments. Do not call directly.
|
||||
* @param a int
|
||||
* @param b int
|
||||
* @return a + b
|
||||
*/
|
||||
public static int ADD(final int a, final int b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of + operator for two long arguments. Do not call directly.
|
||||
* @param a long
|
||||
* @param b long
|
||||
* @return a + b
|
||||
*/
|
||||
public static long ADD(final long a, final long b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized version of + operator for two double arguments. Do not call directly.
|
||||
* @param a double
|
||||
* @param b double
|
||||
* @return a + b
|
||||
*/
|
||||
public static double ADD(final double a, final double b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that ints are addition compatible, i.e. their sum is equal to the sum
|
||||
* of them cast to long. Otherwise the addition will overflow. Do not call directly.
|
||||
*
|
||||
* @param a int
|
||||
* @param b int
|
||||
*
|
||||
* @return true if addition does not overflow
|
||||
*/
|
||||
public static boolean ADDcheck(final int a, final int b) {
|
||||
return (a + b == (long)a + (long)b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkcast used for specialized ops. Do not call directly
|
||||
*
|
||||
* @param type to to check against
|
||||
* @param obj object to check for type
|
||||
*
|
||||
* @return true if type check holds
|
||||
*/
|
||||
public static boolean checkcast(final Class<?> type, final Object obj) {
|
||||
return type.isInstance(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkcast used for specialized ops. Do not call directly
|
||||
*
|
||||
* @param type type to check against
|
||||
* @param objA first object to check against type
|
||||
* @param objB second object to check against type
|
||||
*
|
||||
* @return true if type check holds for both objects
|
||||
*/
|
||||
public static boolean checkcast(final Class<?> type, final Object objA, final Object objB) {
|
||||
return type.isInstance(objA) && type.isInstance(objB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbox a java.lang.Boolean. Do not call directly
|
||||
* @param obj object to cast to int and unbox
|
||||
* @return an int value for the boolean, 1 is true, 0 is false
|
||||
*/
|
||||
public static int unboxZ(final Object obj) {
|
||||
return (boolean)obj ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbox a java.lang.Integer. Do not call directly
|
||||
* @param obj object to cast to int and unbox
|
||||
* @return an int
|
||||
*/
|
||||
public static int unboxI(final Object obj) {
|
||||
return (int)obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbox a java.lang.Long. Do not call directly
|
||||
* @param obj object to cast to long and unbox
|
||||
* @return a long
|
||||
*/
|
||||
public static long unboxJ(final Object obj) {
|
||||
return (long)obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbox a java.lang.Number. Do not call directly
|
||||
* @param obj object to cast to Number and unbox
|
||||
* @return a double
|
||||
*/
|
||||
public static double unboxD(final Object obj) {
|
||||
return ((Number)obj).doubleValue();
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
try {
|
||||
return MH.findStatic(MethodHandles.lookup(), RuntimeCallSite.class, name, MH.type(rtype, types));
|
||||
} catch (final MethodHandleFactory.LookupException e) {
|
||||
return MH.findVirtual(MethodHandles.lookup(), RuntimeCallSite.class, name, MH.type(rtype, types));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
192
nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java
Normal file
192
nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
|
||||
/**
|
||||
* A scope call or get operation that can be shared by several callsites. This generates a static
|
||||
* method that wraps the invokedynamic instructions to get or call scope variables.
|
||||
* The rationale for this is that initial linking of invokedynamic callsites is expensive,
|
||||
* so by sharing them we can reduce startup overhead and allow very large scripts to run that otherwise wouldn't.
|
||||
*
|
||||
* <p>Static methods generated by this class expect two parameters in addition to the parameters of the
|
||||
* function call: The current scope object and the depth of the target scope relative to the scope argument
|
||||
* for when this is known at compile-time (fast-scope access).</p>
|
||||
*
|
||||
* <p>The second argument may be -1 for non-fast-scope symbols, in which case the scope chain is checked
|
||||
* for each call. This may cause callsite invalidation when the shared method is used from different
|
||||
* scopes, but such sharing of non-fast scope calls may still be necessary for very large scripts.</p>
|
||||
*
|
||||
* <p>Scope calls must not be shared between normal callsites and callsites contained in a <tt>with</tt>
|
||||
* statement as this condition is not handled by current guards and will cause a runtime error.</p>
|
||||
*/
|
||||
public class SharedScopeCall {
|
||||
|
||||
/** Threshold for using shared scope calls with fast scope access. */
|
||||
public static final int FAST_SCOPE_CALL_THRESHOLD = 4;
|
||||
/** Threshold for using shared scope calls with slow scope access. */
|
||||
public static final int SLOW_SCOPE_CALL_THRESHOLD = 500;
|
||||
/** Threshold for using shared scope gets with fast scope access. */
|
||||
public static final int FAST_SCOPE_GET_THRESHOLD = 200;
|
||||
|
||||
final Type valueType;
|
||||
final Symbol symbol;
|
||||
final Type returnType;
|
||||
final Type[] paramTypes;
|
||||
final int flags;
|
||||
final boolean isCall;
|
||||
private CompileUnit compileUnit;
|
||||
private String methodName;
|
||||
private String staticSignature;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param symbol the symbol
|
||||
* @param valueType the type of the value
|
||||
* @param returnType the return type
|
||||
* @param paramTypes the function parameter types
|
||||
* @param flags the callsite flags
|
||||
*/
|
||||
SharedScopeCall(final Symbol symbol, final Type valueType, final Type returnType, final Type[] paramTypes, final int flags) {
|
||||
this.symbol = symbol;
|
||||
this.valueType = valueType;
|
||||
this.returnType = returnType;
|
||||
this.paramTypes = paramTypes;
|
||||
this.flags = flags;
|
||||
// If paramTypes is not null this is a call, otherwise it's just a get.
|
||||
this.isCall = paramTypes != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return symbol.hashCode() ^ returnType.hashCode() ^ Arrays.hashCode(paramTypes) ^ flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj instanceof SharedScopeCall) {
|
||||
final SharedScopeCall c = (SharedScopeCall) obj;
|
||||
return symbol.equals(c.symbol)
|
||||
&& flags == c.flags
|
||||
&& returnType.equals(c.returnType)
|
||||
&& Arrays.equals(paramTypes, c.paramTypes);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the compile unit and method name.
|
||||
* @param compileUnit the compile unit
|
||||
* @param compiler the compiler to generate a unique method name
|
||||
*/
|
||||
protected void setClassAndName(final CompileUnit compileUnit, final Compiler compiler) {
|
||||
this.compileUnit = compileUnit;
|
||||
this.methodName = compiler.uniqueName("scopeCall");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the invoke instruction for this shared scope call.
|
||||
* @param method the method emitter
|
||||
*/
|
||||
public void generateInvoke(final MethodEmitter method) {
|
||||
method.invokeStatic(compileUnit.getUnitClassName(), methodName, getStaticSignature());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the method that implements the scope get or call.
|
||||
*/
|
||||
protected void generateScopeCall() {
|
||||
final ClassEmitter classEmitter = compileUnit.getClassEmitter();
|
||||
final EnumSet<ClassEmitter.Flag> methodFlags = EnumSet.of(ClassEmitter.Flag.STATIC);
|
||||
|
||||
// This method expects two fixed parameters in addition to any parameters that may be
|
||||
// passed on to the function: A ScriptObject representing the caller's current scope object,
|
||||
// and an int specifying the distance to the target scope containing the symbol we want to
|
||||
// access, or -1 if this is not known at compile time (e.g. because of a "with" or "eval").
|
||||
|
||||
final MethodEmitter method = classEmitter.method(methodFlags, methodName, getStaticSignature());
|
||||
method.begin();
|
||||
|
||||
// Load correct scope by calling getProto() on the scope argument as often as specified
|
||||
// by the second argument.
|
||||
final MethodEmitter.Label parentLoopStart = new MethodEmitter.Label("parent_loop_start");
|
||||
final MethodEmitter.Label parentLoopDone = new MethodEmitter.Label("parent_loop_done");
|
||||
method.load(Type.OBJECT, 0);
|
||||
method.label(parentLoopStart);
|
||||
method.load(Type.INT, 1);
|
||||
method.iinc(1, -1);
|
||||
method.ifle(parentLoopDone);
|
||||
method.invoke(ScriptObject.GET_PROTO);
|
||||
method._goto(parentLoopStart);
|
||||
method.label(parentLoopDone);
|
||||
|
||||
method.dynamicGet(valueType, symbol.getName(), flags, isCall);
|
||||
|
||||
// If this is a get we're done, otherwise call the value as function.
|
||||
if (isCall) {
|
||||
method.convert(Type.OBJECT);
|
||||
// ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly.
|
||||
method.loadNull();
|
||||
int slot = 2;
|
||||
for (final Type type : paramTypes) {
|
||||
method.load(type, slot++);
|
||||
if (type == Type.NUMBER || type == Type.LONG) slot++;
|
||||
}
|
||||
method.dynamicCall(returnType, paramTypes.length, flags);
|
||||
}
|
||||
|
||||
method._return(returnType);
|
||||
method.end();
|
||||
}
|
||||
|
||||
private String getStaticSignature() {
|
||||
if (staticSignature == null) {
|
||||
if (paramTypes == null) {
|
||||
staticSignature = Type.getMethodDescriptor(returnType, Type.typeFor(ScriptObject.class), Type.INT);
|
||||
} else {
|
||||
final Type[] params = new Type[paramTypes.length + 2];
|
||||
params[0] = Type.typeFor(ScriptObject.class);
|
||||
params[1] = Type.INT;
|
||||
int i = 2;
|
||||
for (Type type : paramTypes) {
|
||||
if (type.isObject()) {
|
||||
type = Type.OBJECT;
|
||||
}
|
||||
params[i++] = type;
|
||||
}
|
||||
staticSignature = Type.getMethodDescriptor(returnType, params);
|
||||
}
|
||||
}
|
||||
return staticSignature;
|
||||
}
|
||||
|
||||
}
|
||||
403
nashorn/src/jdk/nashorn/internal/codegen/Splitter.java
Normal file
403
nashorn/src/jdk/nashorn/internal/codegen/Splitter.java
Normal file
@ -0,0 +1,403 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jdk.nashorn.internal.ir.Block;
|
||||
import jdk.nashorn.internal.ir.BreakNode;
|
||||
import jdk.nashorn.internal.ir.ContinueNode;
|
||||
import jdk.nashorn.internal.ir.DoWhileNode;
|
||||
import jdk.nashorn.internal.ir.ForNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.LabelNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.ReturnNode;
|
||||
import jdk.nashorn.internal.ir.SplitNode;
|
||||
import jdk.nashorn.internal.ir.SwitchNode;
|
||||
import jdk.nashorn.internal.ir.WhileNode;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* Split the IR into smaller compile units.
|
||||
*/
|
||||
public class Splitter extends NodeVisitor {
|
||||
/** Current compiler. */
|
||||
private final Compiler compiler;
|
||||
|
||||
/** IR to be broken down. */
|
||||
private final FunctionNode functionNode;
|
||||
|
||||
/** Compile unit for the main script. */
|
||||
private final CompileUnit scriptCompileUnit;
|
||||
|
||||
/** Cache for calculated block weights. */
|
||||
private final Map<Node, Long> weightCache = new HashMap<>();
|
||||
|
||||
/** Weight threshold for when to start a split. */
|
||||
public static final long SPLIT_THRESHOLD = 32 * 1024;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param compiler the compiler
|
||||
* @param functionNode function node to split
|
||||
*/
|
||||
public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit compileUnit) {
|
||||
this.compiler = compiler;
|
||||
this.functionNode = functionNode;
|
||||
this.scriptCompileUnit = compileUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the split
|
||||
*/
|
||||
void split() {
|
||||
long weight = WeighNodes.weigh(functionNode);
|
||||
|
||||
if (weight >= SPLIT_THRESHOLD) {
|
||||
|
||||
functionNode.accept(this);
|
||||
|
||||
if (functionNode.isSplit()) {
|
||||
// Weight has changed so weigh again, this time using block weight cache
|
||||
weight = WeighNodes.weigh(functionNode, weightCache);
|
||||
}
|
||||
|
||||
if (weight >= SPLIT_THRESHOLD) {
|
||||
weight = splitBlock(functionNode);
|
||||
}
|
||||
|
||||
if (functionNode.isSplit()) {
|
||||
functionNode.accept(new SplitFlowAnalyzer());
|
||||
}
|
||||
}
|
||||
|
||||
assert functionNode.getCompileUnit() == null : "compile unit already set";
|
||||
|
||||
if (functionNode.isScript()) {
|
||||
assert scriptCompileUnit != null : "script compile unit is null";
|
||||
|
||||
functionNode.setCompileUnit(scriptCompileUnit);
|
||||
scriptCompileUnit.addWeight(weight + WeighNodes.FUNCTION_WEIGHT);
|
||||
} else {
|
||||
functionNode.setCompileUnit(findUnit(weight));
|
||||
}
|
||||
|
||||
// Recursively split nested functions
|
||||
final List<FunctionNode> functions = functionNode.getFunctions();
|
||||
|
||||
for (final FunctionNode function : functions) {
|
||||
new Splitter(compiler, function, scriptCompileUnit).split();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this logic to look up compile units in a different way
|
||||
* @param weight weight needed
|
||||
* @return compile unit
|
||||
*/
|
||||
protected CompileUnit findUnit(final long weight) {
|
||||
return compiler.findUnit(weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a block into sub methods.
|
||||
*
|
||||
* @param block Block or function to split.
|
||||
*
|
||||
* @return new weight for the resulting block.
|
||||
*/
|
||||
private long splitBlock(final Block block) {
|
||||
functionNode.setIsSplit();
|
||||
|
||||
final List<Node> splits = new ArrayList<>();
|
||||
List<Node> statements = new ArrayList<>();
|
||||
long statementsWeight = 0;
|
||||
|
||||
for (final Node statement : block.getStatements()) {
|
||||
final long weight = WeighNodes.weigh(statement, weightCache);
|
||||
|
||||
if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
|
||||
if (!statements.isEmpty()) {
|
||||
splits.add(createBlockSplitNode(block, statements, statementsWeight));
|
||||
statements = new ArrayList<>();
|
||||
statementsWeight = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (statement.isTerminal()) {
|
||||
splits.add(statement);
|
||||
} else {
|
||||
statements.add(statement);
|
||||
statementsWeight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (!statements.isEmpty()) {
|
||||
splits.add(createBlockSplitNode(block, statements, statementsWeight));
|
||||
}
|
||||
|
||||
block.setStatements(splits);
|
||||
|
||||
return WeighNodes.weigh(block, weightCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new split node from statements contained in a parent block.
|
||||
*
|
||||
* @param parent Parent block.
|
||||
* @param statements Statements to include.
|
||||
*
|
||||
* @return New split node.
|
||||
*/
|
||||
private SplitNode createBlockSplitNode(final Block parent, final List<Node> statements, final long weight) {
|
||||
final Source source = parent.getSource();
|
||||
final long token = parent.getToken();
|
||||
final int finish = parent.getFinish();
|
||||
final String name = compiler.uniqueName(SPLIT_PREFIX.tag());
|
||||
|
||||
final Block newBlock = new Block(source, token, finish, parent, functionNode);
|
||||
newBlock.setFrame(new Frame(parent.getFrame()));
|
||||
newBlock.setStatements(statements);
|
||||
|
||||
final SplitNode splitNode = new SplitNode(name, functionNode, newBlock);
|
||||
|
||||
splitNode.setCompileUnit(compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
|
||||
|
||||
return splitNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final Block block) {
|
||||
if (block.isCatchBlock()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final long weight = WeighNodes.weigh(block, weightCache);
|
||||
|
||||
if (weight < SPLIT_THRESHOLD) {
|
||||
weightCache.put(block, weight);
|
||||
return null;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final Block block) {
|
||||
assert !block.isCatchBlock();
|
||||
|
||||
// Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have
|
||||
// been split already, so weigh again before splitting.
|
||||
long weight = WeighNodes.weigh(block, weightCache);
|
||||
if (weight >= SPLIT_THRESHOLD) {
|
||||
weight = splitBlock(block);
|
||||
}
|
||||
weightCache.put(block, weight);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Node leave(final LiteralNode literal) {
|
||||
long weight = WeighNodes.weigh(literal);
|
||||
|
||||
if (weight < SPLIT_THRESHOLD) {
|
||||
return literal;
|
||||
}
|
||||
|
||||
functionNode.setIsSplit();
|
||||
|
||||
if (literal instanceof ArrayLiteralNode) {
|
||||
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
|
||||
final Node[] value = arrayLiteralNode.getValue();
|
||||
final int[] postsets = arrayLiteralNode.getPostsets();
|
||||
final List<ArrayUnit> units = new ArrayList<>();
|
||||
|
||||
long totalWeight = 0;
|
||||
int lo = 0;
|
||||
|
||||
for (int i = 0; i < postsets.length; i++) {
|
||||
final int postset = postsets[i];
|
||||
final Node element = value[postset];
|
||||
|
||||
weight = WeighNodes.weigh(element);
|
||||
totalWeight += weight;
|
||||
|
||||
if (totalWeight >= SPLIT_THRESHOLD) {
|
||||
final CompileUnit unit = compiler.findUnit(totalWeight - weight);
|
||||
units.add(new ArrayUnit(unit, lo, i));
|
||||
lo = i;
|
||||
totalWeight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (lo != postsets.length) {
|
||||
final CompileUnit unit = compiler.findUnit(totalWeight);
|
||||
units.add(new ArrayUnit(unit, lo, postsets.length));
|
||||
}
|
||||
|
||||
arrayLiteralNode.setUnits(units);
|
||||
}
|
||||
|
||||
return literal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final FunctionNode node) {
|
||||
final List<Node> statements = node.getStatements();
|
||||
|
||||
for (final Node statement : statements) {
|
||||
statement.accept(this);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static class SplitFlowAnalyzer extends NodeVisitor {
|
||||
|
||||
/** Stack of visited Split nodes, deepest node first. */
|
||||
private final Deque<SplitNode> splitStack;
|
||||
|
||||
/** Map of possible jump targets to containing split node */
|
||||
private final Map<Node,SplitNode> targetNodes = new HashMap<>();
|
||||
|
||||
SplitFlowAnalyzer() {
|
||||
this.splitStack = new LinkedList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final LabelNode labelNode) {
|
||||
registerJumpTarget(labelNode.getBreakNode());
|
||||
registerJumpTarget(labelNode.getContinueNode());
|
||||
return labelNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final WhileNode whileNode) {
|
||||
registerJumpTarget(whileNode);
|
||||
return whileNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final DoWhileNode doWhileNode) {
|
||||
registerJumpTarget(doWhileNode);
|
||||
return doWhileNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final ForNode forNode) {
|
||||
registerJumpTarget(forNode);
|
||||
return forNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final SwitchNode switchNode) {
|
||||
registerJumpTarget(switchNode);
|
||||
return switchNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final ReturnNode returnNode) {
|
||||
for (final SplitNode split : splitStack) {
|
||||
split.setHasReturn(true);
|
||||
}
|
||||
return returnNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final ContinueNode continueNode) {
|
||||
searchJumpTarget(continueNode.getTargetNode(), continueNode.getTargetLabel());
|
||||
return continueNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final BreakNode breakNode) {
|
||||
searchJumpTarget(breakNode.getTargetNode(), breakNode.getTargetLabel());
|
||||
return breakNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final SplitNode splitNode) {
|
||||
splitStack.addFirst(splitNode);
|
||||
return splitNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final SplitNode splitNode) {
|
||||
assert splitNode == splitStack.peekFirst();
|
||||
splitStack.removeFirst();
|
||||
return splitNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the split node containing a potential jump target.
|
||||
* @param targetNode a potential target node.
|
||||
*/
|
||||
private void registerJumpTarget(final Node targetNode) {
|
||||
final SplitNode splitNode = splitStack.peekFirst();
|
||||
if (splitNode != null) {
|
||||
targetNodes.put(targetNode, splitNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a jump target is outside the current split node and its parent split nodes.
|
||||
* @param targetNode the jump target node.
|
||||
* @param targetLabel the jump target label.
|
||||
*/
|
||||
private void searchJumpTarget(final Node targetNode, final MethodEmitter.Label targetLabel) {
|
||||
|
||||
final SplitNode targetSplit = targetNodes.get(targetNode);
|
||||
// Note that targetSplit may be null, indicating that targetNode is in top level method.
|
||||
// In this case we have to add the external jump target to all split nodes.
|
||||
|
||||
for (final SplitNode split : splitStack) {
|
||||
if (split == targetSplit) {
|
||||
break;
|
||||
}
|
||||
final List<MethodEmitter.Label> externalTargets = split.getExternalTargets();
|
||||
if (!externalTargets.contains(targetLabel)) {
|
||||
split.addExternalTarget(targetLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
nashorn/src/jdk/nashorn/internal/codegen/Transform.java
Normal file
33
nashorn/src/jdk/nashorn/internal/codegen/Transform.java
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
/**
|
||||
* Code generation transform
|
||||
*/
|
||||
public interface Transform {
|
||||
//empty
|
||||
}
|
||||
308
nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java
Normal file
308
nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java
Normal file
@ -0,0 +1,308 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jdk.nashorn.internal.ir.AccessNode;
|
||||
import jdk.nashorn.internal.ir.BinaryNode;
|
||||
import jdk.nashorn.internal.ir.Block;
|
||||
import jdk.nashorn.internal.ir.BreakNode;
|
||||
import jdk.nashorn.internal.ir.CallNode;
|
||||
import jdk.nashorn.internal.ir.CatchNode;
|
||||
import jdk.nashorn.internal.ir.ContinueNode;
|
||||
import jdk.nashorn.internal.ir.DoWhileNode;
|
||||
import jdk.nashorn.internal.ir.ExecuteNode;
|
||||
import jdk.nashorn.internal.ir.ForNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.IdentNode;
|
||||
import jdk.nashorn.internal.ir.IfNode;
|
||||
import jdk.nashorn.internal.ir.IndexNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.PropertyNode;
|
||||
import jdk.nashorn.internal.ir.ReferenceNode;
|
||||
import jdk.nashorn.internal.ir.ReturnNode;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode;
|
||||
import jdk.nashorn.internal.ir.SplitNode;
|
||||
import jdk.nashorn.internal.ir.SwitchNode;
|
||||
import jdk.nashorn.internal.ir.ThrowNode;
|
||||
import jdk.nashorn.internal.ir.TryNode;
|
||||
import jdk.nashorn.internal.ir.VarNode;
|
||||
import jdk.nashorn.internal.ir.WhileNode;
|
||||
import jdk.nashorn.internal.ir.WithNode;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
|
||||
/**
|
||||
* Computes the "byte code" weight of an AST segment. This is used
|
||||
* for Splitting too large class files
|
||||
*/
|
||||
public class WeighNodes extends NodeVisitor {
|
||||
/*
|
||||
* Weight constants.
|
||||
*/
|
||||
static final long FUNCTION_WEIGHT = 40;
|
||||
private static final long ACCESS_WEIGHT = 4;
|
||||
private static final long ADD_WEIGHT = 10;
|
||||
private static final long BREAK_WEIGHT = 1;
|
||||
private static final long CALL_WEIGHT = 10;
|
||||
private static final long CATCH_WEIGHT = 10;
|
||||
private static final long CONTINUE_WEIGHT = 1;
|
||||
private static final long IF_WEIGHT = 2;
|
||||
private static final long LITERAL_WEIGHT = 10;
|
||||
private static final long LOOP_WEIGHT = 4;
|
||||
private static final long REFERENCE_WEIGHT = 20;
|
||||
private static final long RETURN_WEIGHT = 2;
|
||||
private static final long SPLIT_WEIGHT = 40;
|
||||
private static final long SWITCH_WEIGHT = 8;
|
||||
private static final long THROW_WEIGHT = 2;
|
||||
private static final long VAR_WEIGHT = 40;
|
||||
private static final long WITH_WEIGHT = 8;
|
||||
|
||||
/** Accumulated weight. */
|
||||
private long weight;
|
||||
|
||||
/** Optional cache for weight of block nodes. */
|
||||
private final Map<Node, Long> weightCache;
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*
|
||||
* @param weightCache cache of already calculated block weights
|
||||
*/
|
||||
private WeighNodes(final Map<Node, Long> weightCache) {
|
||||
super(null, null);
|
||||
this.weightCache = weightCache;
|
||||
}
|
||||
|
||||
static long weigh(final Node node) {
|
||||
final WeighNodes weighNodes = new WeighNodes(null);
|
||||
node.accept(weighNodes);
|
||||
return weighNodes.weight;
|
||||
}
|
||||
|
||||
static long weigh(final Node node, final Map<Node, Long> weightCache) {
|
||||
final WeighNodes weighNodes = new WeighNodes(weightCache);
|
||||
node.accept(weighNodes);
|
||||
return weighNodes.weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final AccessNode accessNode) {
|
||||
weight += ACCESS_WEIGHT;
|
||||
return accessNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final BinaryNode binaryNode) {
|
||||
final TokenType tokenType = binaryNode.tokenType();
|
||||
|
||||
if (tokenType == TokenType.ADD || tokenType == TokenType.ASSIGN_ADD) {
|
||||
weight += ADD_WEIGHT;
|
||||
} else {
|
||||
weight += 1;
|
||||
}
|
||||
|
||||
return binaryNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final Block block) {
|
||||
|
||||
if (weightCache != null && weightCache.containsKey(block)) {
|
||||
weight += weightCache.get(block);
|
||||
return null;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final BreakNode breakNode) {
|
||||
weight += BREAK_WEIGHT;
|
||||
return breakNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final CallNode callNode) {
|
||||
weight += CALL_WEIGHT;
|
||||
return callNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final CatchNode catchNode) {
|
||||
weight += CATCH_WEIGHT;
|
||||
return catchNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final ContinueNode continueNode) {
|
||||
weight += CONTINUE_WEIGHT;
|
||||
return continueNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final DoWhileNode doWhileNode) {
|
||||
weight += LOOP_WEIGHT;
|
||||
return doWhileNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final ExecuteNode executeNode) {
|
||||
return executeNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final ForNode forNode) {
|
||||
weight += LOOP_WEIGHT;
|
||||
return forNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final FunctionNode functionNode) {
|
||||
final List<Node> statements = functionNode.getStatements();
|
||||
|
||||
for (final Node statement : statements) {
|
||||
statement.accept(this);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final IdentNode identNode) {
|
||||
weight += ACCESS_WEIGHT + identNode.getName().length() * 2;
|
||||
return identNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final IfNode ifNode) {
|
||||
weight += IF_WEIGHT;
|
||||
return ifNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final IndexNode indexNode) {
|
||||
weight += ACCESS_WEIGHT;
|
||||
return indexNode;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Node enter(final LiteralNode literalNode) {
|
||||
weight += LITERAL_WEIGHT;
|
||||
|
||||
if (literalNode instanceof ArrayLiteralNode) {
|
||||
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
|
||||
final Node[] value = arrayLiteralNode.getValue();
|
||||
final int[] postsets = arrayLiteralNode.getPostsets();
|
||||
final List<ArrayUnit> units = arrayLiteralNode.getUnits();
|
||||
|
||||
if (units == null) {
|
||||
for (final int postset : postsets) {
|
||||
final Node element = value[postset];
|
||||
|
||||
if (element != null) {
|
||||
element.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return literalNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final PropertyNode propertyNode) {
|
||||
weight += LITERAL_WEIGHT;
|
||||
return propertyNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final ReferenceNode referenceNode) {
|
||||
weight += REFERENCE_WEIGHT;
|
||||
return referenceNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final ReturnNode returnNode) {
|
||||
weight += RETURN_WEIGHT;
|
||||
return returnNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final RuntimeNode runtimeNode) {
|
||||
weight += CALL_WEIGHT;
|
||||
return runtimeNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node enter(final SplitNode splitNode) {
|
||||
weight += SPLIT_WEIGHT;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final SwitchNode switchNode) {
|
||||
weight += SWITCH_WEIGHT;
|
||||
return switchNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final ThrowNode throwNode) {
|
||||
weight += THROW_WEIGHT;
|
||||
return throwNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final TryNode tryNode) {
|
||||
weight += THROW_WEIGHT;
|
||||
return tryNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final VarNode varNode) {
|
||||
weight += VAR_WEIGHT;
|
||||
return varNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final WhileNode whileNode) {
|
||||
weight += LOOP_WEIGHT;
|
||||
return whileNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leave(final WithNode withNode) {
|
||||
weight += WITH_WEIGHT;
|
||||
return withNode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
|
||||
import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.CodeGenerator;
|
||||
import jdk.nashorn.internal.codegen.MethodEmitter;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
|
||||
|
||||
/**
|
||||
* Analyze an object's characteristics for appropriate code generation. This
|
||||
* is used for functions and for objects. A field object take a set of values which
|
||||
* to assign to the various fields in the object. This is done by the generated code
|
||||
*
|
||||
* @param <T> the value type for the fields being written on object creation, e.g. Node
|
||||
* @see jdk.nashorn.internal.ir.Node
|
||||
*/
|
||||
public abstract class FieldObjectCreator<T> extends ObjectCreator {
|
||||
/** array of corresponding values to symbols (null for no values) */
|
||||
private final List<T> values;
|
||||
|
||||
/** call site flags to be used for invocations */
|
||||
private final int callSiteFlags;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param codegen code generator
|
||||
* @param keys keys for fields in object
|
||||
* @param symbols symbols for fields in object
|
||||
* @param values list of values corresponding to keys
|
||||
*/
|
||||
public FieldObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final List<T> values) {
|
||||
this(codegen, keys, symbols, values, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param codegen code generator
|
||||
* @param keys keys for fields in object
|
||||
* @param symbols symbols for fields in object
|
||||
* @param values values (or null where no value) to be written to the fields
|
||||
* @param isScope is this a scope object
|
||||
* @param isVarArg is this a vararg object
|
||||
*/
|
||||
public FieldObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final List<T> values, final boolean isScope, final boolean isVarArg) {
|
||||
super(codegen, keys, symbols, isScope, isVarArg);
|
||||
this.values = values;
|
||||
this.callSiteFlags = codegen.getCallSiteFlags();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an object.
|
||||
*
|
||||
* @param method the method emitter
|
||||
*/
|
||||
@Override
|
||||
public void makeObject(final MethodEmitter method) {
|
||||
makeMap();
|
||||
|
||||
method._new(getClassName()).dup(); // create instance
|
||||
loadMap(method); //load the map
|
||||
|
||||
if (isScope()) {
|
||||
method.loadScope();
|
||||
|
||||
if (isVarArg()) {
|
||||
method.loadArguments();
|
||||
method.invoke(constructorNoLookup(getClassName(), PropertyMap.class, ScriptObject.class, ARGUMENTS.type()));
|
||||
} else {
|
||||
method.invoke(constructorNoLookup(getClassName(), PropertyMap.class, ScriptObject.class));
|
||||
}
|
||||
} else {
|
||||
method.invoke(constructorNoLookup(getClassName(), PropertyMap.class));
|
||||
}
|
||||
|
||||
// Set values.
|
||||
final Iterator<Symbol> symbolIter = symbols.iterator();
|
||||
final Iterator<String> keyIter = keys.iterator();
|
||||
final Iterator<T> valueIter = values.iterator();
|
||||
|
||||
while (symbolIter.hasNext()) {
|
||||
final Symbol symbol = symbolIter.next();
|
||||
final String key = keyIter.next();
|
||||
final T value = valueIter.next();
|
||||
|
||||
if (symbol != null && value != null) {
|
||||
final int index = ArrayIndex.getArrayIndexNoThrow(key);
|
||||
|
||||
if (index < 0) {
|
||||
putField(method, key, symbol.getFieldIndex(), value);
|
||||
} else {
|
||||
putSlot(method, index, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Technique for loading an initial value. Defined by anonymous subclasses in code gen.
|
||||
*
|
||||
* @param value Value to load.
|
||||
*/
|
||||
protected abstract void loadValue(T value);
|
||||
|
||||
/**
|
||||
* Determine the type of a value. Defined by anonymous subclasses in code gen.
|
||||
*
|
||||
* @param value Value to inspect.
|
||||
*
|
||||
* @return Value type.
|
||||
*/
|
||||
protected abstract Type getValueType(T value);
|
||||
|
||||
/**
|
||||
* Store a value in a field of the generated class object.
|
||||
*
|
||||
* @param method Script method.
|
||||
* @param key Property key.
|
||||
* @param fieldIndex Field number.
|
||||
* @param value Value to store.
|
||||
*/
|
||||
private void putField(final MethodEmitter method, final String key, final int fieldIndex, final T value) {
|
||||
method.dup();
|
||||
|
||||
loadValue(value);
|
||||
|
||||
final Type valueType = getValueType(value);
|
||||
// for example when we have a with scope
|
||||
if (valueType.isObject() || valueType.isBoolean()) {
|
||||
method.convert(OBJECT);
|
||||
}
|
||||
|
||||
method.convert(OBJECT);
|
||||
method.putField(getClassName(), ObjectClassGenerator.getFieldName(fieldIndex, Type.OBJECT), typeDescriptor(Object.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a value in an indexed slot of a generated class object.
|
||||
*
|
||||
* @param method Script method.
|
||||
* @param index Slot index.
|
||||
* @param value Value to store.
|
||||
*/
|
||||
private void putSlot(final MethodEmitter method, final int index, final T value) {
|
||||
method.dup();
|
||||
method.load(index);
|
||||
loadValue(value);
|
||||
method.dynamicSetIndex(callSiteFlags);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.HANDLE_STATIC;
|
||||
import static jdk.nashorn.internal.codegen.Compiler.SCRIPTOBJECT_IMPL_OBJECT;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.CodeGenerator;
|
||||
import jdk.nashorn.internal.codegen.FunctionSignature;
|
||||
import jdk.nashorn.internal.codegen.MethodEmitter;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.IdentNode;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* Analyze a function object's characteristics for appropriate code
|
||||
* generation. This generates code for the instantiation of ScriptFunction:s
|
||||
*/
|
||||
public class FunctionObjectCreator extends ObjectCreator {
|
||||
|
||||
private final FunctionNode functionNode;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param codegen the code generator
|
||||
* @param functionNode the function node to turn into a ScriptFunction implementation
|
||||
* @param keys initial keys for the object map
|
||||
* @param symbols corresponding initial symbols for object map
|
||||
*/
|
||||
public FunctionObjectCreator(final CodeGenerator codegen, final FunctionNode functionNode, final List<String> keys, final List<Symbol> symbols) {
|
||||
super(codegen, keys, symbols, false, false);
|
||||
this.functionNode = functionNode;
|
||||
}
|
||||
|
||||
private void loadHandle(final MethodEmitter method, final String signature) {
|
||||
method.loadHandle(functionNode.getCompileUnit().getUnitClassName(), functionNode.getName(), signature, EnumSet.of(HANDLE_STATIC)); // function
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit code for creating the object
|
||||
*
|
||||
* @param method the method emitter
|
||||
*/
|
||||
@Override
|
||||
public void makeObject(final MethodEmitter method) {
|
||||
makeMap();
|
||||
|
||||
final IdentNode identNode = functionNode.getIdent();
|
||||
final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString();
|
||||
final long firstToken = functionNode.getFirstToken();
|
||||
final long lastToken = functionNode.getLastToken();
|
||||
final int position = Token.descPosition(firstToken);
|
||||
final int length = Token.descPosition(lastToken) - position + Token.descLength(lastToken);
|
||||
final long token = Token.toDesc(TokenType.FUNCTION, position, length);
|
||||
|
||||
/*
|
||||
* Instantiate the function object, must be referred to by name as
|
||||
* class is not available at compile time
|
||||
*/
|
||||
method._new(SCRIPTOBJECT_IMPL_OBJECT).dup();
|
||||
method.load(functionNode.isAnonymous() ? "" : identNode.getName());
|
||||
loadHandle(method, signature);
|
||||
method.loadScope();
|
||||
method.getStatic(compileUnit.getUnitClassName(), SOURCE.tag(), SOURCE.descriptor());
|
||||
method.load(token);
|
||||
method.loadHandle(getClassName(), ALLOCATE.tag(), methodDescriptor(ScriptObject.class, PropertyMap.class), EnumSet.of(HANDLE_STATIC));
|
||||
|
||||
/*
|
||||
* Emit code for the correct property map for the object
|
||||
*/
|
||||
loadMap(method);
|
||||
|
||||
/*
|
||||
* Invoke the constructor
|
||||
*/
|
||||
method.load(functionNode.needsCallee());
|
||||
method.load(functionNode.isStrictMode());
|
||||
method.invoke(constructorNoLookup(SCRIPTOBJECT_IMPL_OBJECT,
|
||||
String.class,
|
||||
MethodHandle.class,
|
||||
ScriptObject.class,
|
||||
Source.class,
|
||||
long.class,
|
||||
MethodHandle.class,
|
||||
PropertyMap.class,
|
||||
boolean.class,
|
||||
boolean.class));
|
||||
|
||||
|
||||
if (functionNode.isVarArg()) {
|
||||
method.dup();
|
||||
method.load(functionNode.getParameters().size());
|
||||
method.invoke(ScriptFunction.SET_ARITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
163
nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java
Normal file
163
nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
|
||||
import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.PRIMITIVE_TYPE;
|
||||
import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.runtime.AccessorProperty;
|
||||
import jdk.nashorn.internal.runtime.Property;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
|
||||
|
||||
/**
|
||||
* Class that creates PropertyMap sent to script object constructors.
|
||||
*/
|
||||
public class MapCreator {
|
||||
/** Object structure for objects associated with this map */
|
||||
private final Class<?> structure;
|
||||
|
||||
/** key set for object map */
|
||||
private final String[] keys;
|
||||
|
||||
/** corresponding symbol set for object map */
|
||||
private final Symbol[] symbols;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param structure structure to generate map for (a JO$ subclass)
|
||||
* @param keys list of keys for map
|
||||
* @param symbols list of symbols for map
|
||||
*/
|
||||
public MapCreator(final Class<?> structure, final List<String> keys, final List<Symbol> symbols) {
|
||||
final int size = keys.size();
|
||||
|
||||
this.structure = structure;
|
||||
this.keys = keys.toArray(new String[size]);
|
||||
this.symbols = symbols.toArray(new Symbol[size]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a property map based on a set of fields.
|
||||
*
|
||||
* @param isVarArg is this a vararg object map
|
||||
*
|
||||
* @return New map populated with accessor properties.
|
||||
*/
|
||||
public PropertyMap makeMap(final boolean isVarArg) {
|
||||
final List<Property> properties = new ArrayList<>();
|
||||
|
||||
assert keys != null;
|
||||
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
final String key = keys[i];
|
||||
final Symbol symbol = symbols[i];
|
||||
|
||||
if (symbol != null && !ArrayIndex.isIndexKey(key)) {
|
||||
final Property property = initHandle(key, symbol.getFieldIndex(), symbol, isVarArg);
|
||||
properties.add(property);
|
||||
}
|
||||
}
|
||||
|
||||
return PropertyMap.newMap(structure, properties);
|
||||
}
|
||||
|
||||
private Property initHandle(final String key, final int fieldIndex, final Symbol symbol, final boolean isVarArg) {
|
||||
assert symbol != null;
|
||||
final boolean isParam = symbol.isParam();
|
||||
|
||||
final String fieldNameObject = ObjectClassGenerator.getFieldName(fieldIndex, Type.OBJECT);
|
||||
final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(fieldIndex, ObjectClassGenerator.PRIMITIVE_TYPE);
|
||||
|
||||
MethodHandle primitiveGetter = null;
|
||||
MethodHandle primitiveSetter = null;
|
||||
MethodHandle objectGetter;
|
||||
MethodHandle objectSetter;
|
||||
|
||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
if (isParam && isVarArg) {
|
||||
final MethodHandle arguments = MH.getter(MethodHandles.lookup(), structure, "arguments", Object.class);
|
||||
final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class));
|
||||
objectGetter = MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, fieldIndex);
|
||||
objectSetter = MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, fieldIndex);
|
||||
} else {
|
||||
objectGetter = MH.getter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
|
||||
objectSetter = MH.setter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
|
||||
if (!OBJECT_FIELDS_ONLY) {
|
||||
primitiveGetter = MH.getter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
|
||||
primitiveSetter = MH.setter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
|
||||
}
|
||||
}
|
||||
|
||||
return new AccessorProperty(key, getPropertyFlags(symbol, isVarArg), objectGetter, objectSetter, primitiveGetter, primitiveSetter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute property flags given local state of a field. Maybe be overridden and extended,
|
||||
* as is the case in {@link ObjectMapCreator}
|
||||
*
|
||||
* @param symbol symbol to check
|
||||
* @param isVarArg is this a vararg
|
||||
*
|
||||
* @return flags to use for fields
|
||||
*/
|
||||
protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) {
|
||||
final boolean isParam = symbol.isParam();
|
||||
int flags = 0;
|
||||
|
||||
if (isParam || isVarArg) {
|
||||
flags |= Property.IS_ALWAYS_OBJECT;
|
||||
if (isParam) {
|
||||
flags |= Property.IS_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol.isScope()) {
|
||||
flags |= Property.NOT_CONFIGURABLE;
|
||||
}
|
||||
|
||||
if (symbol.canBePrimitive()) {
|
||||
flags |= Property.CAN_BE_PRIMITIVE;
|
||||
}
|
||||
|
||||
if (symbol.canBeUndefined()) {
|
||||
flags |= Property.CAN_BE_UNDEFINED;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,762 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.objects;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.Compiler.SCRIPTS_PACKAGE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_ARGUMENTS;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_SCOPE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_PREFIX;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.MAP;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.className;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
|
||||
import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.ClassEmitter;
|
||||
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
|
||||
import jdk.nashorn.internal.codegen.MethodEmitter;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.AccessorProperty;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.DebugLogger;
|
||||
import jdk.nashorn.internal.runtime.FunctionScope;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.options.Options;
|
||||
|
||||
/**
|
||||
* Generates the ScriptObject subclass structure with fields for a user objects.
|
||||
*/
|
||||
public final class ObjectClassGenerator {
|
||||
|
||||
/**
|
||||
* Marker for scope parameters.
|
||||
*/
|
||||
public static final String SCOPE_MARKER = "P";
|
||||
|
||||
/**
|
||||
* Debug field logger
|
||||
* Should we print debugging information for fields when they are generated and getters/setters are called?
|
||||
*/
|
||||
public static final DebugLogger LOG = new DebugLogger("fields", "nashorn.fields.debug");
|
||||
|
||||
/**
|
||||
* is field debugging enabled. Several modules in codegen and properties use this, hence
|
||||
* public access.
|
||||
*/
|
||||
public static final boolean DEBUG_FIELDS = LOG.isEnabled();
|
||||
|
||||
/**
|
||||
* Should the runtime only use java.lang.Object slots for fields? If this is false, the representation
|
||||
* will be a primitive 64-bit long value used for all primitives and a java.lang.Object for references.
|
||||
* This introduces a larger number of method handles in the system, as we need to have different getters
|
||||
* and setters for the different fields. Currently this introduces significant overhead in Hotspot.
|
||||
*
|
||||
* This is engineered to plug into the TaggedArray implementation, when it's done.
|
||||
*/
|
||||
public static final boolean OBJECT_FIELDS_ONLY = !Options.getBooleanProperty("nashorn.fields.dual");
|
||||
|
||||
/** The field types in the system */
|
||||
private static final List<Type> FIELD_TYPES = new LinkedList<>();
|
||||
|
||||
/** What type is the primitive type in dual representation */
|
||||
public static final Type PRIMITIVE_TYPE = Type.LONG;
|
||||
|
||||
/**
|
||||
* The list of field types that we support - one type creates one field. This is currently either
|
||||
* LONG + OBJECT or just OBJECT for classic mode.
|
||||
*/
|
||||
static {
|
||||
if (!OBJECT_FIELDS_ONLY) {
|
||||
System.err.println("WARNING!!! Running with primitive fields - there is untested functionality!");
|
||||
FIELD_TYPES.add(PRIMITIVE_TYPE);
|
||||
}
|
||||
FIELD_TYPES.add(Type.OBJECT);
|
||||
}
|
||||
|
||||
/** The context */
|
||||
private final Context context;
|
||||
|
||||
/**
|
||||
* The list of available accessor types in width order. This order is used for type guesses narrow->wide
|
||||
* in the dual--fields world
|
||||
*/
|
||||
public static final List<Type> ACCESSOR_TYPES = Collections.unmodifiableList(
|
||||
Arrays.asList(
|
||||
Type.INT,
|
||||
Type.LONG,
|
||||
Type.NUMBER,
|
||||
Type.OBJECT));
|
||||
|
||||
//these are hard coded for speed and so that we can switch on them
|
||||
private static final int TYPE_INT_INDEX = 0; //getAccessorTypeIndex(int.class);
|
||||
private static final int TYPE_LONG_INDEX = 1; //getAccessorTypeIndex(long.class);
|
||||
private static final int TYPE_DOUBLE_INDEX = 2; //getAccessorTypeIndex(double.class);
|
||||
private static final int TYPE_OBJECT_INDEX = 3; //getAccessorTypeIndex(Object.class);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context a context
|
||||
*/
|
||||
public ObjectClassGenerator(final Context context) {
|
||||
this.context = context;
|
||||
assert context != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a type of an accessor, return its index in [0..getNumberOfAccessorTypes())
|
||||
*
|
||||
* @param type the type
|
||||
*
|
||||
* @return the accessor index, or -1 if no accessor of this type exists
|
||||
*/
|
||||
public static int getAccessorTypeIndex(final Type type) {
|
||||
return getAccessorTypeIndex(type.getTypeClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a class of an accessor, return its index in [0..getNumberOfAccessorTypes())
|
||||
*
|
||||
* Note that this is hardcoded with respect to the dynamic contents of the accessor
|
||||
* types array for speed. Hotspot got stuck with this as 5% of the runtime in
|
||||
* a benchmark when it looped over values and increased an index counter. :-(
|
||||
*
|
||||
* @param type the type
|
||||
*
|
||||
* @return the accessor index, or -1 if no accessor of this type exists
|
||||
*/
|
||||
public static int getAccessorTypeIndex(final Class<?> type) {
|
||||
if (type == int.class) {
|
||||
return 0;
|
||||
} else if (type == long.class) {
|
||||
return 1;
|
||||
} else if (type == double.class) {
|
||||
return 2;
|
||||
} else if (!type.isPrimitive()) {
|
||||
return 3;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of accessor types available.
|
||||
*
|
||||
* @return number of accessor types in system
|
||||
*/
|
||||
public static int getNumberOfAccessorTypes() {
|
||||
return ACCESSOR_TYPES.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the accessor type based on its index in [0..getNumberOfAccessorTypes())
|
||||
* Indexes are ordered narrower->wider / optimistic->pessimistic. Invalidations always
|
||||
* go to a type of higher index
|
||||
*
|
||||
* @param index accessor type index
|
||||
*
|
||||
* @return a type corresponding to the index.
|
||||
*/
|
||||
|
||||
public static Type getAccessorType(final int index) {
|
||||
return ACCESSOR_TYPES.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class name for JavaScript objects with fieldCount fields.
|
||||
*
|
||||
* @param fieldCount Number of fields to allocate.
|
||||
*
|
||||
* @return The class name.
|
||||
*/
|
||||
public static String getClassName(final int fieldCount) {
|
||||
return fieldCount != 0 ? SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag() + fieldCount :
|
||||
SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class name for JavaScript scope with fieldCount fields and
|
||||
* paramCount parameters.
|
||||
*
|
||||
* @param fieldCount Number of fields to allocate.
|
||||
* @param paramCount Number of parameters to allocate
|
||||
*
|
||||
* @return The class name.
|
||||
*/
|
||||
public static String getClassName(final int fieldCount, final int paramCount) {
|
||||
return SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag() + fieldCount + SCOPE_MARKER + paramCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a field based on number and type.
|
||||
*
|
||||
* @param fieldIndex Ordinal of field.
|
||||
* @param type Type of field.
|
||||
*
|
||||
* @return The field name.
|
||||
*/
|
||||
public static String getFieldName(final int fieldIndex, final Type type) {
|
||||
return type.getDescriptor().substring(0, 1) + fieldIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* In the world of Object fields, we also have no undefined SwitchPoint, to reduce as much potential
|
||||
* MethodHandle overhead as possible. In that case, we explicitly need to assign undefined to fields
|
||||
* when we initialize them.
|
||||
*
|
||||
* @param init constructor to generate code in
|
||||
* @param className name of class
|
||||
* @param fieldNames fields to initialize to undefined, where applicable
|
||||
*/
|
||||
private static void initializeToUndefined(final MethodEmitter init, final String className, final List<String> fieldNames) {
|
||||
if (fieldNames.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// always initialize fields to undefined, even with --dual-fields. Then it's ok to
|
||||
// remember things like "widest set type" in properties, and if it's object, don't
|
||||
// add any special "return undefined" getters, saving an invalidation
|
||||
init.load(Type.OBJECT, THIS.slot());
|
||||
init.loadUndefined(Type.OBJECT);
|
||||
|
||||
final Iterator<String> iter = fieldNames.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final String fieldName = iter.next();
|
||||
if (iter.hasNext()) {
|
||||
init.dup2();
|
||||
}
|
||||
init.putField(className, fieldName, Type.OBJECT.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the byte codes for a JavaScript object class or scope.
|
||||
* Class name is a function of number of fields and number of param
|
||||
* fields
|
||||
*
|
||||
* @param descriptor Descriptor pulled from class name.
|
||||
*
|
||||
* @return Byte codes for generated class.
|
||||
*/
|
||||
public byte[] generate(final String descriptor) {
|
||||
final String[] counts = descriptor.split(SCOPE_MARKER);
|
||||
final int fieldCount = Integer.valueOf(counts[0]);
|
||||
|
||||
if (counts.length == 1) {
|
||||
return generate(fieldCount);
|
||||
}
|
||||
|
||||
final int paramCount = Integer.valueOf(counts[1]);
|
||||
|
||||
return generate(fieldCount, paramCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the byte codes for a JavaScript object class with fieldCount fields.
|
||||
*
|
||||
* @param fieldCount Number of fields in the JavaScript object.
|
||||
*
|
||||
* @return Byte codes for generated class.
|
||||
*/
|
||||
public byte[] generate(final int fieldCount) {
|
||||
final String className = getClassName(fieldCount);
|
||||
final String superName = className(ScriptObject.class);
|
||||
final ClassEmitter classEmitter = newClassEmitter(className, superName);
|
||||
final List<String> initFields = addFields(classEmitter, fieldCount);
|
||||
|
||||
final MethodEmitter init = newInitMethod(classEmitter);
|
||||
initializeToUndefined(init, className, initFields);
|
||||
init.returnVoid();
|
||||
init.end();
|
||||
|
||||
newEmptyInit(classEmitter, className);
|
||||
newAllocate(classEmitter, className);
|
||||
|
||||
return toByteArray(classEmitter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the byte codes for a JavaScript scope class with fieldCount fields
|
||||
* and paramCount parameters.
|
||||
*
|
||||
* @param fieldCount Number of fields in the JavaScript scope.
|
||||
* @param paramCount Number of parameters in the JavaScript scope
|
||||
* .
|
||||
* @return Byte codes for generated class.
|
||||
*/
|
||||
public byte[] generate(final int fieldCount, final int paramCount) {
|
||||
final String className = getClassName(fieldCount, paramCount);
|
||||
final String superName = className(FunctionScope.class);
|
||||
final ClassEmitter classEmitter = newClassEmitter(className, superName);
|
||||
final List<String> initFields = addFields(classEmitter, fieldCount);
|
||||
|
||||
final MethodEmitter init = newInitScopeMethod(classEmitter);
|
||||
initializeToUndefined(init, className, initFields);
|
||||
init.returnVoid();
|
||||
init.end();
|
||||
|
||||
final MethodEmitter initWithArguments = newInitScopeWithArgumentsMethod(classEmitter);
|
||||
initializeToUndefined(initWithArguments, className, initFields);
|
||||
initWithArguments.returnVoid();
|
||||
initWithArguments.end();
|
||||
|
||||
return toByteArray(classEmitter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the needed fields.
|
||||
*
|
||||
* @param classEmitter Open class emitter.
|
||||
* @param fieldCount Number of fields.
|
||||
*
|
||||
* @return List fields that need to be initialized.
|
||||
*/
|
||||
private static List<String> addFields(final ClassEmitter classEmitter, final int fieldCount) {
|
||||
final List<String> initFields = new LinkedList<>();
|
||||
|
||||
for (int i = 0; i < fieldCount; i++) {
|
||||
for (final Type type : FIELD_TYPES) {
|
||||
final String fieldName = getFieldName(i, type);
|
||||
classEmitter.field(fieldName, type.getTypeClass());
|
||||
|
||||
if (type == Type.OBJECT) {
|
||||
initFields.add(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return initFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new class emitter.
|
||||
*
|
||||
* @param className Name of JavaScript class.
|
||||
*
|
||||
* @return Open class emitter.
|
||||
*/
|
||||
private ClassEmitter newClassEmitter(final String className, final String superName) {
|
||||
final ClassEmitter classEmitter = new ClassEmitter(context, className, superName);
|
||||
classEmitter.begin();
|
||||
|
||||
return classEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new <init> method.
|
||||
*
|
||||
* @param classEmitter Open class emitter.
|
||||
*
|
||||
* @return Open method emitter.
|
||||
*/
|
||||
private static MethodEmitter newInitMethod(final ClassEmitter classEmitter) {
|
||||
final MethodEmitter init = classEmitter.init(PropertyMap.class);
|
||||
init.begin();
|
||||
init.load(Type.OBJECT, THIS.slot());
|
||||
init.load(Type.OBJECT, MAP.slot());
|
||||
init.invoke(constructorNoLookup(ScriptObject.class, PropertyMap.class));
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new <init> method for scopes.
|
||||
* @param classEmitter Open class emitter.
|
||||
* @return Open method emitter.
|
||||
*/
|
||||
private static MethodEmitter newInitScopeMethod(final ClassEmitter classEmitter) {
|
||||
final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class);
|
||||
init.begin();
|
||||
init.load(Type.OBJECT, THIS.slot());
|
||||
init.load(Type.OBJECT, MAP.slot());
|
||||
init.load(Type.OBJECT, INIT_SCOPE.slot());
|
||||
init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class));
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new <init> method for scopes with arguments.
|
||||
* @param classEmitter Open class emitter.
|
||||
* @return Open method emitter.
|
||||
*/
|
||||
private static MethodEmitter newInitScopeWithArgumentsMethod(final ClassEmitter classEmitter) {
|
||||
final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, Object.class);
|
||||
init.begin();
|
||||
init.load(Type.OBJECT, THIS.slot());
|
||||
init.load(Type.OBJECT, MAP.slot());
|
||||
init.load(Type.OBJECT, INIT_SCOPE.slot());
|
||||
init.load(Type.OBJECT, INIT_ARGUMENTS.slot());
|
||||
init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, Object.class));
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an empty <init> method to the JavaScript class.
|
||||
*
|
||||
* @param classEmitter Open class emitter.
|
||||
* @param className Name of JavaScript class.
|
||||
*/
|
||||
private static void newEmptyInit(final ClassEmitter classEmitter, final String className) {
|
||||
final MethodEmitter emptyInit = classEmitter.init();
|
||||
emptyInit.begin();
|
||||
emptyInit.load(Type.OBJECT, THIS.slot());
|
||||
emptyInit.loadNull();
|
||||
emptyInit.invoke(constructorNoLookup(className, PropertyMap.class));
|
||||
emptyInit.returnVoid();
|
||||
emptyInit.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an empty <init> method to the JavaScript class.
|
||||
*
|
||||
* @param classEmitter Open class emitter.
|
||||
* @param className Name of JavaScript class.
|
||||
*/
|
||||
private static void newAllocate(final ClassEmitter classEmitter, final String className) {
|
||||
final MethodEmitter allocate = classEmitter.method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), ALLOCATE.tag(), ScriptObject.class, PropertyMap.class);
|
||||
allocate.begin();
|
||||
allocate._new(className);
|
||||
allocate.dup();
|
||||
allocate.load(Type.typeFor(PropertyMap.class), 0);
|
||||
allocate.invoke(constructorNoLookup(className, PropertyMap.class));
|
||||
allocate._return();
|
||||
allocate.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the byte codes for a generated JavaScript class.
|
||||
*
|
||||
* @param classEmitter Open class emitter.
|
||||
* @return Byte codes for the class.
|
||||
*/
|
||||
private byte[] toByteArray(final ClassEmitter classEmitter) {
|
||||
classEmitter.end();
|
||||
|
||||
final byte[] code = classEmitter.toByteArray();
|
||||
|
||||
if (context != null && context._print_code) {
|
||||
ClassEmitter.disassemble(context, code);
|
||||
}
|
||||
|
||||
if (context != null && context._verify_code) {
|
||||
ClassEmitter.verify(context, code);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
/** Double to long bits, used with --dual-fields for primitive double values */
|
||||
private static final MethodHandle PACK_DOUBLE =
|
||||
MH.explicitCastArguments(MH.findStatic(MethodHandles.publicLookup(), Double.class, "doubleToRawLongBits", MH.type(long.class, double.class)), MH.type(long.class, double.class));
|
||||
|
||||
/** double bits to long, used with --dual-fields for primitive double values */
|
||||
private static MethodHandle UNPACK_DOUBLE =
|
||||
MH.findStatic(MethodHandles.publicLookup(), Double.class, "longBitsToDouble", MH.type(double.class, long.class));
|
||||
|
||||
/** object conversion quickies with JS semantics - used for return value and parameter filter */
|
||||
private static MethodHandle[] CONVERT_OBJECT = {
|
||||
JSType.TO_INT32.methodHandle(),
|
||||
JSType.TO_UINT32.methodHandle(),
|
||||
JSType.TO_NUMBER.methodHandle(),
|
||||
null
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a primitiveGetter (optional for non dual fields) and an objectSetter that retrieve
|
||||
* the primitive and object version of a field respectively, return one with the correct
|
||||
* method type and the correct filters. For example, if the value is stored as a double
|
||||
* and we want an Object getter, in the dual fields world we'd pick the primitiveGetter,
|
||||
* which reads a long, use longBitsToDouble on the result to unpack it, and then change the
|
||||
* return type to Object, boxing it. In the objects only world there are only object fields,
|
||||
* primtives are boxed when asked for them and we don't need to bother with primitive encoding
|
||||
* (or even undefined, which if forType==null) representation, so we just return whatever is
|
||||
* in the object field. The object field is always initiated to Undefined, so here, where we have
|
||||
* the representation for Undefined in all our bits, this is not a problem.
|
||||
* <p>
|
||||
* Representing undefined in a primitive is hard, for an int there aren't enough bits, for a long
|
||||
* we could limit the width of a representation, and for a double (as long as it is stored as long,
|
||||
* as all NaNs will turn into QNaN on ia32, which is one bit pattern, we should use a special NaN).
|
||||
* Naturally we could have special undefined values for all types which mean "go look in a wider field",
|
||||
* but the guards needed on every getter took too much time.
|
||||
* <p>
|
||||
* To see how this is used, look for example in {@link AccessorProperty#getGetter}
|
||||
* <p>
|
||||
* @param forType representation of the underlying type in the field, null if undefined
|
||||
* @param type type to retrieve it as
|
||||
* @param primitiveGetter getter to read the primitive version of this field (null if Objects Only)
|
||||
* @param objectGetter getter to read the object version of this field
|
||||
*
|
||||
* @return getter for the given representation that returns the given type
|
||||
*/
|
||||
public static MethodHandle createGetter(final Class<?> forType, final Class<?> type, final MethodHandle primitiveGetter, final MethodHandle objectGetter) {
|
||||
final int fti = forType == null ? -1 : getAccessorTypeIndex(forType);
|
||||
final int ti = getAccessorTypeIndex(type);
|
||||
|
||||
if (fti == TYPE_OBJECT_INDEX || OBJECT_FIELDS_ONLY) {
|
||||
if (ti == TYPE_OBJECT_INDEX) {
|
||||
return objectGetter;
|
||||
}
|
||||
|
||||
return MH.filterReturnValue(objectGetter, CONVERT_OBJECT[ti]);
|
||||
}
|
||||
|
||||
assert !OBJECT_FIELDS_ONLY;
|
||||
if (forType == null) {
|
||||
return GET_UNDEFINED[ti];
|
||||
}
|
||||
|
||||
final MethodType pmt = primitiveGetter.type();
|
||||
|
||||
switch (fti) {
|
||||
case TYPE_INT_INDEX:
|
||||
case TYPE_LONG_INDEX:
|
||||
switch (ti) {
|
||||
case TYPE_INT_INDEX:
|
||||
//get int while an int, truncating cast of long value
|
||||
return MH.explicitCastArguments(primitiveGetter, pmt.changeReturnType(int.class));
|
||||
case TYPE_LONG_INDEX:
|
||||
return primitiveGetter;
|
||||
default:
|
||||
return MH.asType(primitiveGetter, pmt.changeReturnType(type));
|
||||
}
|
||||
case TYPE_DOUBLE_INDEX:
|
||||
final MethodHandle getPrimitiveAsDouble = MH.filterReturnValue(primitiveGetter, UNPACK_DOUBLE);
|
||||
switch (ti) {
|
||||
case TYPE_INT_INDEX:
|
||||
case TYPE_LONG_INDEX:
|
||||
return MH.explicitCastArguments(getPrimitiveAsDouble, pmt.changeReturnType(type));
|
||||
case TYPE_DOUBLE_INDEX:
|
||||
return getPrimitiveAsDouble;
|
||||
default:
|
||||
return MH.asType(getPrimitiveAsDouble, pmt.changeReturnType(Object.class));
|
||||
}
|
||||
default:
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final MethodHandle IS_TYPE_GUARD = findOwnMH("isType", boolean.class, Class.class, Object.class);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isType(final Class<?> boxedForType, final Object x) {
|
||||
return x.getClass() == boxedForType;
|
||||
}
|
||||
|
||||
private static Class<? extends Number> getBoxedType(final Class<?> forType) {
|
||||
if (forType == int.class) {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
if (forType == long.class) {
|
||||
return Long.class;
|
||||
}
|
||||
|
||||
if (forType == double.class) {
|
||||
return Double.class;
|
||||
}
|
||||
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are setting boxed types (because the compiler couldn't determine which they were) to
|
||||
* a primitive field, we can reuse the primitive field getter, as long as we are setting an element
|
||||
* of the same boxed type as the primitive type representation
|
||||
*
|
||||
* @param forType the current type
|
||||
* @param primitiveSetter primitive setter for the current type with an element of the current type
|
||||
* @param objectSetter the object setter
|
||||
*
|
||||
* @return method handle that checks if the element to be set is of the currenttype, even though it's boxed
|
||||
* and instead of using the generic object setter, that would blow up the type and invalidate the map,
|
||||
* unbox it and call the primitive setter instead
|
||||
*/
|
||||
public static MethodHandle createGuardBoxedPrimitiveSetter(final Class<?> forType, final MethodHandle primitiveSetter, final MethodHandle objectSetter) {
|
||||
final Class<? extends Number> boxedForType = getBoxedType(forType);
|
||||
//object setter that checks for primitive if current type is primitive
|
||||
|
||||
return MH.guardWithTest(
|
||||
MH.insertArguments(
|
||||
MH.dropArguments(
|
||||
IS_TYPE_GUARD,
|
||||
1,
|
||||
Object.class),
|
||||
0,
|
||||
boxedForType),
|
||||
MH.asType(
|
||||
primitiveSetter,
|
||||
objectSetter.type()),
|
||||
objectSetter);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is similar to the {@link ObjectClassGenerator#createGetter} function. Performs
|
||||
* the necessary operations to massage a setter operand of type {@code type} to
|
||||
* fit into the primitive field (if primitive and dual fields is enabled) or into
|
||||
* the object field (box if primitive and dual fields is disabled)
|
||||
*
|
||||
* @param forType representation of the underlying object
|
||||
* @param type representation of field to write, and setter signature
|
||||
* @param primitiveSetter setter that writes to the primitive field (null if Objects Only)
|
||||
* @param objectSetter setter that writes to the object field
|
||||
*
|
||||
* @return the setter for the given representation that takes a {@code type}
|
||||
*/
|
||||
public static MethodHandle createSetter(final Class<?> forType, final Class<?> type, final MethodHandle primitiveSetter, final MethodHandle objectSetter) {
|
||||
assert forType != null;
|
||||
|
||||
final int fti = getAccessorTypeIndex(forType);
|
||||
final int ti = getAccessorTypeIndex(type);
|
||||
|
||||
if (fti == TYPE_OBJECT_INDEX || OBJECT_FIELDS_ONLY) {
|
||||
if (ti == TYPE_OBJECT_INDEX) {
|
||||
return objectSetter;
|
||||
}
|
||||
|
||||
return MH.asType(objectSetter, objectSetter.type().changeParameterType(1, type));
|
||||
}
|
||||
|
||||
assert !OBJECT_FIELDS_ONLY;
|
||||
|
||||
final MethodType pmt = primitiveSetter.type();
|
||||
|
||||
switch (fti) {
|
||||
case TYPE_INT_INDEX:
|
||||
case TYPE_LONG_INDEX:
|
||||
switch (ti) {
|
||||
case TYPE_INT_INDEX:
|
||||
return MH.asType(primitiveSetter, pmt.changeParameterType(1, int.class));
|
||||
case TYPE_LONG_INDEX:
|
||||
return primitiveSetter;
|
||||
case TYPE_DOUBLE_INDEX:
|
||||
return MH.filterArguments(primitiveSetter, 1, PACK_DOUBLE);
|
||||
default:
|
||||
return objectSetter;
|
||||
}
|
||||
case TYPE_DOUBLE_INDEX:
|
||||
if (ti == TYPE_OBJECT_INDEX) {
|
||||
return objectSetter;
|
||||
}
|
||||
return MH.asType(MH.filterArguments(primitiveSetter, 1, PACK_DOUBLE), pmt.changeParameterType(1, type));
|
||||
default:
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Provide generic getters and setters for undefined types. If a type is undefined, all
|
||||
// and marshals the set to the correct setter depending on the type of the value being set.
|
||||
// Note that there are no actual undefined versions of int, long and double in JavaScript,
|
||||
// but executing toInt32, toLong and toNumber always returns a working result, 0, 0L or NaN
|
||||
//
|
||||
|
||||
/** The value of Undefined cast to an int32 */
|
||||
public static final int UNDEFINED_INT = 0;
|
||||
/** The value of Undefined cast to a long */
|
||||
public static final long UNDEFINED_LONG = 0L;
|
||||
/** The value of Undefined cast to a double */
|
||||
public static final double UNDEFINED_DOUBLE = Double.NaN;
|
||||
|
||||
/**
|
||||
* Compute type name for correct undefined getter
|
||||
* @param type the type
|
||||
* @return name of getter
|
||||
*/
|
||||
private static String typeName(final Type type) {
|
||||
String name = type.getTypeClass().getName();
|
||||
final int dot = name.lastIndexOf('.');
|
||||
if (dot != -1) {
|
||||
name = name.substring(dot + 1);
|
||||
}
|
||||
return Character.toUpperCase(name.charAt(0)) + name.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles for undefined getters of the different types
|
||||
*/
|
||||
private static final MethodHandle[] GET_UNDEFINED = new MethodHandle[ObjectClassGenerator.getNumberOfAccessorTypes()];
|
||||
|
||||
/**
|
||||
* Used to wrap getters for undefined values, where this matters. Currently only in dual fields.
|
||||
* If an object starts out as undefined it needs special getters until it has been assigned
|
||||
* something the first time
|
||||
*
|
||||
* @param returnType type to cast the undefined to
|
||||
*
|
||||
* @return undefined as returnType
|
||||
*/
|
||||
public static MethodHandle getUndefined(final Class<?> returnType) {
|
||||
return GET_UNDEFINED[ObjectClassGenerator.getAccessorTypeIndex(returnType)];
|
||||
}
|
||||
|
||||
static {
|
||||
int pos = 0;
|
||||
for (final Type type : ACCESSOR_TYPES) {
|
||||
GET_UNDEFINED[pos++] = findOwnMH("getUndefined" + typeName(type), type.getTypeClass(), Object.class);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static int getUndefinedInt(final Object obj) {
|
||||
return UNDEFINED_INT;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static long getUndefinedLong(final Object obj) {
|
||||
return UNDEFINED_LONG;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static double getUndefinedDouble(final Object obj) {
|
||||
return UNDEFINED_DOUBLE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object getUndefinedObject(final Object obj) {
|
||||
return ScriptRuntime.UNDEFINED;
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
return MH.findStatic(MethodHandles.lookup(), ObjectClassGenerator.class, name, MH.type(rtype, types));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.objects;
|
||||
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.CodeGenerator;
|
||||
import jdk.nashorn.internal.codegen.CompileUnit;
|
||||
import jdk.nashorn.internal.codegen.Compiler;
|
||||
import jdk.nashorn.internal.codegen.MethodEmitter;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
|
||||
/**
|
||||
* Base class for object creation code generation.
|
||||
*/
|
||||
public abstract class ObjectCreator {
|
||||
|
||||
/** Compile unit for this ObjectCreator, see CompileUnit */
|
||||
protected final CompileUnit compileUnit;
|
||||
|
||||
/** List of keys to initiate in this ObjectCreator */
|
||||
protected final List<String> keys;
|
||||
|
||||
/** List of symbols to initiate in this ObjectCreator */
|
||||
protected final List<Symbol> symbols;
|
||||
|
||||
/** Code generator */
|
||||
protected final CodeGenerator codegen;
|
||||
|
||||
private final boolean isScope;
|
||||
private final boolean isVarArg;
|
||||
private int fieldCount;
|
||||
private int paramCount;
|
||||
private String fieldObjectClassName;
|
||||
private Class<?> fieldObjectClass;
|
||||
private PropertyMap propertyMap;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param codegen the code generator
|
||||
* @param keys the keys
|
||||
* @param symbols the symbols corresponding to keys, same index
|
||||
* @param isScope is this object scope
|
||||
* @param isVarArg is this object var arg
|
||||
*/
|
||||
protected ObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final boolean isScope, final boolean isVarArg) {
|
||||
this.codegen = codegen;
|
||||
this.compileUnit = codegen.getCurrentCompileUnit();
|
||||
this.keys = keys;
|
||||
this.symbols = symbols;
|
||||
this.isScope = isScope;
|
||||
this.isVarArg = isVarArg;
|
||||
|
||||
countFields();
|
||||
findClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tally the number of fields and parameters.
|
||||
*/
|
||||
private void countFields() {
|
||||
for (final Symbol symbol : this.symbols) {
|
||||
if (symbol != null) {
|
||||
if (isVarArg() && symbol.isParam()) {
|
||||
symbol.setFieldIndex(paramCount++);
|
||||
} else {
|
||||
symbol.setFieldIndex(fieldCount++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate (or indirectly create) the object container class.
|
||||
*/
|
||||
private void findClass() {
|
||||
fieldObjectClassName = isScope() ?
|
||||
ObjectClassGenerator.getClassName(fieldCount, paramCount) :
|
||||
ObjectClassGenerator.getClassName(fieldCount);
|
||||
|
||||
try {
|
||||
this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
|
||||
} catch (final ClassNotFoundException e) {
|
||||
throw new AssertionError("Nashorn has encountered an internal error. Structure can not be created.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate code for making the object.
|
||||
* @param method Script method.
|
||||
*/
|
||||
public abstract void makeObject(final MethodEmitter method);
|
||||
|
||||
/**
|
||||
* Create a new MapCreator
|
||||
* @param clazz type of MapCreator
|
||||
* @return map creator instantiated by type
|
||||
*/
|
||||
protected MapCreator newMapCreator(final Class<?> clazz) {
|
||||
return new MapCreator(clazz, keys, symbols);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the property map appropriate for the object.
|
||||
*/
|
||||
protected void makeMap() {
|
||||
if (keys.isEmpty()) { //empty map
|
||||
propertyMap = PropertyMap.newMap(fieldObjectClass);
|
||||
return;
|
||||
}
|
||||
|
||||
propertyMap = newMapCreator(fieldObjectClass).makeMap(isVarArg());
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit the correct map for the object.
|
||||
* @param method method emitter
|
||||
* @return the method emitter
|
||||
*/
|
||||
protected MethodEmitter loadMap(final MethodEmitter method) {
|
||||
codegen.loadConstant(propertyMap);
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class name for the object class,
|
||||
* e.g. {@code com.nashorn.oracle.scripts.JO$2P0}
|
||||
*
|
||||
* @return script class name
|
||||
*/
|
||||
public String getClassName() {
|
||||
return fieldObjectClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a scope object
|
||||
* @return true if scope
|
||||
*/
|
||||
protected boolean isScope() {
|
||||
return isScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a vararg object
|
||||
* @return true if vararg
|
||||
*/
|
||||
protected boolean isVarArg() {
|
||||
return isVarArg;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.objects;
|
||||
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.runtime.Property;
|
||||
|
||||
/**
|
||||
* This map creator is used to guarantee that all properties start out as
|
||||
* object types. Only semantically significant in the -Dnashorn.fields.dual=true world,
|
||||
* where we want to avoid invalidation upon initialization e.g. for var x = {a:"str"};
|
||||
*/
|
||||
|
||||
public class ObjectMapCreator extends MapCreator {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param structure structure for object class
|
||||
* @param keys keys in object
|
||||
* @param symbols symbols in object corresponding to keys
|
||||
*/
|
||||
public ObjectMapCreator(final Class<?> structure, final List<String> keys, final List<Symbol> symbols) {
|
||||
super(structure, keys, symbols);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) {
|
||||
return super.getPropertyFlags(symbol, isVarArg) | Property.IS_ALWAYS_OBJECT;
|
||||
}
|
||||
}
|
||||
107
nashorn/src/jdk/nashorn/internal/codegen/types/ArrayType.java
Normal file
107
nashorn/src/jdk/nashorn/internal/codegen/types/ArrayType.java
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.AASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ARRAYLENGTH;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
|
||||
/**
|
||||
* This is an array type, i.e. OBJECT_ARRAY, NUMBER_ARRAY.
|
||||
*/
|
||||
public class ArrayType extends ObjectType implements BytecodeArrayOps {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param clazz the Java class representation of the array
|
||||
*/
|
||||
protected ArrayType(final Class<?> clazz) {
|
||||
super(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element type of the array elements e.g. for OBJECT_ARRAY, this is OBJECT
|
||||
*
|
||||
* @return the element type
|
||||
*/
|
||||
public Type getElementType() {
|
||||
return Type.typeFor(getTypeClass().getComponentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void astore(final MethodVisitor method) {
|
||||
method.visitInsn(AASTORE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type aload(final MethodVisitor method) {
|
||||
method.visitInsn(AALOAD);
|
||||
return getElementType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type arraylength(final MethodVisitor method) {
|
||||
method.visitInsn(ARRAYLENGTH);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type newarray(final MethodVisitor method) {
|
||||
method.visitTypeInsn(ANEWARRAY, getElementType().getInternalName());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type newarray(final MethodVisitor method, final int dims) {
|
||||
method.visitMultiANewArrayInsn(getInternalName(), dims);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type load(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(ALOAD, slot);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "array<elementType=" + getElementType().getTypeClass().getSimpleName() + '>';
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type convert(final MethodVisitor method, final Type to) {
|
||||
assert to.isObject();
|
||||
assert !to.isArray() || ((ArrayType)to).getElementType() == getElementType();
|
||||
return to;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
/**
|
||||
* This class represents a numeric type that can be used for bit operations.
|
||||
*/
|
||||
public abstract class BitwiseType extends NumericType implements BytecodeBitwiseOps {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param name name of type
|
||||
* @param clazz Java class used to represent type
|
||||
* @param weight weight of type
|
||||
* @param slots number of bytecode slots this type takes up
|
||||
*/
|
||||
protected BitwiseType(final String name, final Class<?> clazz, final int weight, final int slots) {
|
||||
super(name, clazz, weight, slots);
|
||||
}
|
||||
}
|
||||
161
nashorn/src/jdk/nashorn/internal/codegen/types/BooleanType.java
Normal file
161
nashorn/src/jdk/nashorn/internal/codegen/types/BooleanType.java
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
|
||||
/**
|
||||
* The boolean type class
|
||||
*/
|
||||
public final class BooleanType extends Type {
|
||||
|
||||
private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Boolean.class, "valueOf", Boolean.class, boolean.class);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
protected BooleanType() {
|
||||
super("boolean", boolean.class, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type nextWider() {
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getBoxedType() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadUndefined(final MethodVisitor method) {
|
||||
method.visitLdcInsn(ObjectClassGenerator.UNDEFINED_INT);
|
||||
return BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadEmpty(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void _return(final MethodVisitor method) {
|
||||
method.visitInsn(IRETURN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type load(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(ILOAD, slot);
|
||||
return BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(ISTORE, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type ldc(final MethodVisitor method, final Object c) {
|
||||
assert c instanceof Boolean;
|
||||
method.visitInsn((Boolean) c ? ICONST_1 : ICONST_0);
|
||||
return BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type convert(final MethodVisitor method, final Type to) {
|
||||
if (isEquivalentTo(to)) {
|
||||
return to;
|
||||
}
|
||||
|
||||
if (to.isNumber()) {
|
||||
convert(method, OBJECT);
|
||||
invokeStatic(method, JSType.TO_NUMBER);
|
||||
} else if (to.isInteger()) {
|
||||
return to; // do nothing.
|
||||
} else if (to.isLong()) {
|
||||
convert(method, OBJECT);
|
||||
invokeStatic(method, JSType.TO_UINT32);
|
||||
} else if (to.isLong()) {
|
||||
convert(method, OBJECT);
|
||||
invokeStatic(method, JSType.TO_LONG);
|
||||
} else if (to.isString()) {
|
||||
invokeStatic(method, VALUE_OF);
|
||||
invokeStatic(method, JSType.TO_PRIMITIVE);
|
||||
invokeStatic(method, JSType.TO_STRING);
|
||||
} else if (to.isObject()) {
|
||||
invokeStatic(method, VALUE_OF);
|
||||
} else {
|
||||
assert false : "Illegal conversion " + this + " -> " + to;
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type add(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
|
||||
/**
|
||||
* Array operations, not supported by all ops
|
||||
*/
|
||||
interface BytecodeArrayOps {
|
||||
|
||||
/**
|
||||
* Load an array element given that the array and its index are already on
|
||||
* the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return the array element type
|
||||
*
|
||||
*/
|
||||
Type aload(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Store an array element given that the array and its index and the element
|
||||
* are on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
*/
|
||||
void astore(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Generate an array length operation
|
||||
*
|
||||
* @param method method method visitor
|
||||
* @return length of the array
|
||||
*/
|
||||
Type arraylength(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Create a new array of this array type and length on stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return the type of the array
|
||||
*/
|
||||
Type newarray(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Create a new multi array of this array type and allocate the number of
|
||||
* dimensions given
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param dims number of dimensions
|
||||
* @return the type of the new array
|
||||
*/
|
||||
Type newarray(MethodVisitor method, int dims);
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
|
||||
/**
|
||||
* Bitwise operations not supported by all types
|
||||
*/
|
||||
interface BytecodeBitwiseOps {
|
||||
|
||||
/**
|
||||
* Pop and logically shift the two values on top of the stack (steps, value)
|
||||
* right and push the result on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return result type
|
||||
*/
|
||||
Type shr(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop and arithmetically shift of the two values on top of the stack
|
||||
* (steps, value) right and push the result on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return result type
|
||||
*/
|
||||
Type sar(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop and logically shift of the two values on top of the stack (steps,
|
||||
* value) left and push the result on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return result type
|
||||
*/
|
||||
Type shl(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop and AND the two values on top of the stack and push the result on the
|
||||
* stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return result type
|
||||
*/
|
||||
Type and(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop and OR the two values on top of the stack and push the result on the
|
||||
* stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return result type
|
||||
*/
|
||||
Type or(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop and XOR the two values on top of the stack and push the result on the
|
||||
* stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return result type
|
||||
*/
|
||||
Type xor(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Comparison with int return value, e.g. LCMP.
|
||||
*
|
||||
* @param method the method visitor
|
||||
* @return int return value
|
||||
*/
|
||||
Type cmp(MethodVisitor method);
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
|
||||
/**
|
||||
* Numeric operations, not supported by all types
|
||||
*/
|
||||
interface BytecodeNumericOps {
|
||||
|
||||
/**
|
||||
* Pop and negate the value on top of the stack and push the result
|
||||
*
|
||||
* @param method method visitor
|
||||
*
|
||||
* @return result type
|
||||
*/
|
||||
Type neg(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop two values on top of the stack and subtract the first from the
|
||||
* second, pushing the result on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
*
|
||||
* @return result type
|
||||
*/
|
||||
Type sub(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop and multiply the two values on top of the stack and push the result
|
||||
* on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
*
|
||||
* @return result type
|
||||
*/
|
||||
Type mul(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop two values on top of the stack and divide the first with the second,
|
||||
* pushing the result on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
*
|
||||
* @return result type
|
||||
*/
|
||||
Type div(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Pop two values on top of the stack and compute the modulo of the first
|
||||
* with the second, pushing the result on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
*
|
||||
* @return result type
|
||||
*/
|
||||
Type rem(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Comparison with int return value, e.g. LCMP, DCMP.
|
||||
*
|
||||
* @param method the method visitor
|
||||
* @param isCmpG is this a double style cmpg
|
||||
*
|
||||
* @return int return value
|
||||
*/
|
||||
Type cmp(MethodVisitor method, boolean isCmpG);
|
||||
}
|
||||
158
nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeOps.java
Normal file
158
nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeOps.java
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for byte code generation for all runtime types. Each
|
||||
* type implements this interface and provides the type specific
|
||||
* operations to do the generic things described herein.
|
||||
*
|
||||
* The bytecode ops are coupled to a MethodVisitor from ASM for
|
||||
* byte code generation. They know nothing about our MethodGenerator,
|
||||
* which is the abstraction for working with Nashorn JS types
|
||||
* For exmaple, anything like "two or one slots" for a type, which
|
||||
* is represented in bytecode and ASM, is abstracted away in the
|
||||
* MethodGenerator. There you just say "dup" or "store".
|
||||
*
|
||||
* @see Type
|
||||
* @see MethodVisitor
|
||||
*/
|
||||
interface BytecodeOps {
|
||||
|
||||
/**
|
||||
* Duplicate top entry of stack. If a too large depth is
|
||||
* given, so that there are no possible bytecode instructions
|
||||
* available to generate the dup sequence, null is returned.
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param depth how far should the copy be pushed down
|
||||
*
|
||||
* @return the type at the top of the stack or null
|
||||
*/
|
||||
Type dup(MethodVisitor method, int depth);
|
||||
|
||||
/**
|
||||
* Pop an entry of this type from the top of the bytecode
|
||||
* stack. This works regardless of what category this type
|
||||
* is
|
||||
*
|
||||
* @param method method visitor
|
||||
*
|
||||
* @return the popped type
|
||||
*/
|
||||
Type pop(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Swap this type with the bytecode stack with the one below
|
||||
* Generate appropriate code no matter the categories of the
|
||||
* two types
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param other the type below this one on the stack
|
||||
*
|
||||
* @return the other type
|
||||
*/
|
||||
Type swap(MethodVisitor method, Type other);
|
||||
|
||||
/**
|
||||
* Pop two values on top of the stack and add the
|
||||
* first to the second, pushing the result on the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @return result type
|
||||
*/
|
||||
Type add(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Load a variable from a local slot to the stack
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param slot the slot to load
|
||||
*
|
||||
* @return the type that was loaded
|
||||
*/
|
||||
Type load(MethodVisitor method, int slot);
|
||||
|
||||
/**
|
||||
* Store a variable from the stack to a local slot
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param slot the slot to store to
|
||||
*/
|
||||
void store(MethodVisitor method, int slot);
|
||||
|
||||
/**
|
||||
* Load a constant to the stack.
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param c the value of the constant
|
||||
*
|
||||
* @return the type at the top of the stack after load
|
||||
*/
|
||||
Type ldc(MethodVisitor method, Object c);
|
||||
|
||||
/**
|
||||
* Load the "undefined" value to the stack. Note that
|
||||
* there may be different representations of this for
|
||||
* e.g. doubles and objects. Abstraction removes this
|
||||
*
|
||||
* @param method method visitor.
|
||||
*
|
||||
* @return the undefined type at the top of the stack
|
||||
*/
|
||||
Type loadUndefined(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Load the "empty" value to the stack.
|
||||
*
|
||||
* @param method method visitor.
|
||||
* @return the undefined type at the top of the stack
|
||||
*/
|
||||
Type loadEmpty(MethodVisitor method);
|
||||
|
||||
/**
|
||||
* Generate code that pops and casts the element on top of the
|
||||
* stack to another type, given as parameter
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param to the type to cast to
|
||||
*
|
||||
* @return the to type
|
||||
*/
|
||||
Type convert(MethodVisitor method, Type to);
|
||||
|
||||
/**
|
||||
* Return the parameter on top of the stack
|
||||
* from a method
|
||||
*
|
||||
* @param method the method visitor
|
||||
*/
|
||||
void _return(MethodVisitor method);
|
||||
|
||||
}
|
||||
260
nashorn/src/jdk/nashorn/internal/codegen/types/IntType.java
Normal file
260
nashorn/src/jdk/nashorn/internal/codegen/types/IntType.java
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.I2D;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.I2L;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IADD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IAND;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_2;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_3;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_4;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_5;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_M1;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IDIV;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IMUL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.INEG;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IOR;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IREM;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ISHL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ISHR;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ISUB;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IUSHR;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IXOR;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator;
|
||||
|
||||
/**
|
||||
* Type class: INT
|
||||
*/
|
||||
class IntType extends BitwiseType {
|
||||
|
||||
private static final CompilerConstants.Call TO_STRING = staticCallNoLookup(Integer.class, "toString", String.class, int.class);
|
||||
private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Integer.class, "valueOf", Integer.class, int.class);
|
||||
|
||||
protected IntType() {
|
||||
super("int", int.class, 2, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type nextWider() {
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getBoxedType() {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type ldc(final MethodVisitor method, final Object c) {
|
||||
assert c instanceof Integer;
|
||||
|
||||
final int value = ((Integer) c).intValue();
|
||||
|
||||
switch (value) {
|
||||
case -1:
|
||||
method.visitInsn(ICONST_M1);
|
||||
break;
|
||||
case 0:
|
||||
method.visitInsn(ICONST_0);
|
||||
break;
|
||||
case 1:
|
||||
method.visitInsn(ICONST_1);
|
||||
break;
|
||||
case 2:
|
||||
method.visitInsn(ICONST_2);
|
||||
break;
|
||||
case 3:
|
||||
method.visitInsn(ICONST_3);
|
||||
break;
|
||||
case 4:
|
||||
method.visitInsn(ICONST_4);
|
||||
break;
|
||||
case 5:
|
||||
method.visitInsn(ICONST_5);
|
||||
break;
|
||||
default:
|
||||
if (value == (byte) value) {
|
||||
method.visitIntInsn(BIPUSH, value);
|
||||
} else if (value == (short) value) {
|
||||
method.visitIntInsn(SIPUSH, value);
|
||||
} else {
|
||||
method.visitLdcInsn(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Type.INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type convert(final MethodVisitor method, final Type to) {
|
||||
if (to.isEquivalentTo(this)) {
|
||||
return to;
|
||||
}
|
||||
|
||||
if (to.isNumber()) {
|
||||
method.visitInsn(I2D);
|
||||
} else if (to.isLong()) {
|
||||
method.visitInsn(I2L);
|
||||
} else if (to.isBoolean()) {
|
||||
//nop
|
||||
} else if (to.isString()) {
|
||||
invokeStatic(method, TO_STRING);
|
||||
} else if (to.isObject()) {
|
||||
invokeStatic(method, VALUE_OF);
|
||||
} else {
|
||||
assert false : "Illegal conversion " + this + " -> " + to;
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type add(final MethodVisitor method) {
|
||||
method.visitInsn(IADD);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type shr(final MethodVisitor method) {
|
||||
method.visitInsn(IUSHR);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type sar(final MethodVisitor method) {
|
||||
method.visitInsn(ISHR);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type shl(final MethodVisitor method) {
|
||||
method.visitInsn(ISHL);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type and(final MethodVisitor method) {
|
||||
method.visitInsn(IAND);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type or(final MethodVisitor method) {
|
||||
method.visitInsn(IOR);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type xor(final MethodVisitor method) {
|
||||
method.visitInsn(IXOR);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type load(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(ILOAD, slot);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(ISTORE, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type sub(final MethodVisitor method) {
|
||||
method.visitInsn(ISUB);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type mul(final MethodVisitor method) {
|
||||
method.visitInsn(IMUL);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type div(final MethodVisitor method) {
|
||||
method.visitInsn(IDIV);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type rem(final MethodVisitor method) {
|
||||
method.visitInsn(IREM);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type neg(final MethodVisitor method) {
|
||||
method.visitInsn(INEG);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void _return(final MethodVisitor method) {
|
||||
method.visitInsn(IRETURN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadUndefined(final MethodVisitor method) {
|
||||
method.visitLdcInsn(ObjectClassGenerator.UNDEFINED_INT);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadEmpty(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type cmp(final MethodVisitor method, final boolean isCmpG) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type cmp(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
229
nashorn/src/jdk/nashorn/internal/codegen/types/LongType.java
Normal file
229
nashorn/src/jdk/nashorn/internal/codegen/types/LongType.java
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.L2D;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.L2I;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LADD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LAND;
|
||||
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.LCONST_1;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LDIV;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LMUL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LNEG;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LOR;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LREM;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LSHL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LSHR;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LSTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LSUB;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LUSHR;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LXOR;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator;
|
||||
|
||||
/**
|
||||
* Type class: LONG
|
||||
*/
|
||||
class LongType extends BitwiseType {
|
||||
|
||||
private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Long.class, "valueOf", Long.class, long.class);
|
||||
|
||||
protected LongType(final String name) {
|
||||
super(name, long.class, 3, 2);
|
||||
}
|
||||
|
||||
protected LongType() {
|
||||
this("long");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type nextWider() {
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getBoxedType() {
|
||||
return Long.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type cmp(final MethodVisitor method) {
|
||||
method.visitInsn(LCMP);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type load(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(LLOAD, slot);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(LSTORE, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type ldc(final MethodVisitor method, final Object c) {
|
||||
assert c instanceof Long;
|
||||
|
||||
final long value = (Long) c;
|
||||
|
||||
if (value == 0L) {
|
||||
method.visitInsn(LCONST_0);
|
||||
} else if (value == 1L) {
|
||||
method.visitInsn(LCONST_1);
|
||||
} else {
|
||||
method.visitLdcInsn(c);
|
||||
}
|
||||
|
||||
return Type.LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type convert(final MethodVisitor method, final Type to) {
|
||||
if (isEquivalentTo(to)) {
|
||||
return to;
|
||||
}
|
||||
|
||||
if (to.isNumber()) {
|
||||
method.visitInsn(L2D);
|
||||
} else if (to.isInteger()) {
|
||||
method.visitInsn(L2I);
|
||||
} else if (to.isBoolean()) {
|
||||
method.visitInsn(L2I);
|
||||
} else if (to.isObject()) {
|
||||
invokeStatic(method, VALUE_OF);
|
||||
} else {
|
||||
assert false : "Illegal conversion " + this + " -> " + to;
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type add(final MethodVisitor method) {
|
||||
method.visitInsn(LADD);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type sub(final MethodVisitor method) {
|
||||
method.visitInsn(LSUB);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type mul(final MethodVisitor method) {
|
||||
method.visitInsn(LMUL);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type div(final MethodVisitor method) {
|
||||
method.visitInsn(LDIV);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type rem(final MethodVisitor method) {
|
||||
method.visitInsn(LREM);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type shr(final MethodVisitor method) {
|
||||
method.visitInsn(LUSHR);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type sar(final MethodVisitor method) {
|
||||
method.visitInsn(LSHR);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type shl(final MethodVisitor method) {
|
||||
method.visitInsn(LSHL);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type and(final MethodVisitor method) {
|
||||
method.visitInsn(LAND);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type or(final MethodVisitor method) {
|
||||
method.visitInsn(LOR);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type xor(final MethodVisitor method) {
|
||||
method.visitInsn(LXOR);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type neg(final MethodVisitor method) {
|
||||
method.visitInsn(LNEG);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void _return(final MethodVisitor method) {
|
||||
method.visitInsn(LRETURN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadUndefined(final MethodVisitor method) {
|
||||
method.visitLdcInsn(ObjectClassGenerator.UNDEFINED_LONG);
|
||||
return LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadEmpty(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type cmp(final MethodVisitor method, final boolean isCmpG) {
|
||||
return cmp(method);
|
||||
}
|
||||
}
|
||||
177
nashorn/src/jdk/nashorn/internal/codegen/types/NumberType.java
Normal file
177
nashorn/src/jdk/nashorn/internal/codegen/types/NumberType.java
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DADD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DCMPG;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DCMPL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_1;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DDIV;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DLOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DMUL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DNEG;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DREM;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DSTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DSUB;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
|
||||
class NumberType extends NumericType {
|
||||
|
||||
private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Double.class, "valueOf", Double.class, double.class);
|
||||
|
||||
protected NumberType() {
|
||||
super("double", double.class, 4, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type nextWider() {
|
||||
return OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getBoxedType() {
|
||||
return Double.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type cmp(final MethodVisitor method, final boolean isCmpG) {
|
||||
method.visitInsn(isCmpG ? DCMPG : DCMPL);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type load(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(DLOAD, slot);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(DSTORE, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadUndefined(final MethodVisitor method) {
|
||||
method.visitLdcInsn(ObjectClassGenerator.UNDEFINED_DOUBLE);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadEmpty(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type ldc(final MethodVisitor method, final Object c) {
|
||||
assert c instanceof Double;
|
||||
|
||||
final double value = (Double) c;
|
||||
|
||||
if (Double.doubleToLongBits(value) == 0L) { // guard against -0.0
|
||||
method.visitInsn(DCONST_0);
|
||||
} else if (value == 1.0) {
|
||||
method.visitInsn(DCONST_1);
|
||||
} else {
|
||||
method.visitLdcInsn(value);
|
||||
}
|
||||
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type convert(final MethodVisitor method, final Type to) {
|
||||
if (isEquivalentTo(to)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (to.isInteger()) {
|
||||
invokeStatic(method, JSType.TO_INT32_D);
|
||||
} else if (to.isLong()) {
|
||||
invokeStatic(method, JSType.TO_INT64_D);
|
||||
} else if (to.isBoolean()) {
|
||||
invokeStatic(method, JSType.TO_BOOLEAN_D);
|
||||
} else if (to.isString()) {
|
||||
invokeStatic(method, JSType.TO_STRING_D);
|
||||
} else if (to.isObject()) {
|
||||
invokeStatic(method, VALUE_OF);
|
||||
} else {
|
||||
assert false : "Illegal conversion " + this + " -> " + to;
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type add(final MethodVisitor method) {
|
||||
method.visitInsn(DADD);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type sub(final MethodVisitor method) {
|
||||
method.visitInsn(DSUB);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type mul(final MethodVisitor method) {
|
||||
method.visitInsn(DMUL);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type div(final MethodVisitor method) {
|
||||
method.visitInsn(DDIV);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type rem(final MethodVisitor method) {
|
||||
method.visitInsn(DREM);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type neg(final MethodVisitor method) {
|
||||
method.visitInsn(DNEG);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void _return(final MethodVisitor method) {
|
||||
method.visitInsn(DRETURN);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
/**
|
||||
* This is a numeric type, i.e. NUMBER, LONG, INT, INT32.
|
||||
*/
|
||||
public abstract class NumericType extends Type implements BytecodeNumericOps {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param name name of type
|
||||
* @param clazz Java class used to represent type
|
||||
* @param weight weight of type
|
||||
* @param slots number of bytecode slots this type takes up
|
||||
*/
|
||||
protected NumericType(final String name, final Class<?> clazz, final int weight, final int slots) {
|
||||
super(name, clazz, weight, slots);
|
||||
}
|
||||
}
|
||||
174
nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java
Normal file
174
nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.className;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Undefined;
|
||||
|
||||
/**
|
||||
* Type class: OBJECT This is the object type, used for all object types. It can
|
||||
* contain a class that is a more specialized object
|
||||
*/
|
||||
class ObjectType extends Type {
|
||||
|
||||
protected ObjectType() {
|
||||
this(Object.class);
|
||||
}
|
||||
|
||||
protected ObjectType(final Class<?> clazz) {
|
||||
super("object",
|
||||
clazz,
|
||||
clazz == Object.class ? Type.MAX_WEIGHT : 10,
|
||||
1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "object" + (getTypeClass() != Object.class ? "<type=" + getTypeClass().getSimpleName() + '>' : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type add(final MethodVisitor method) {
|
||||
invokeStatic(method, ScriptRuntime.ADD);
|
||||
return Type.OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type load(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(ALOAD, slot);
|
||||
|
||||
if (slot == CompilerConstants.THIS.slot()) {
|
||||
return Type.THIS;
|
||||
}
|
||||
|
||||
return Type.OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(final MethodVisitor method, final int slot) {
|
||||
assert slot != -1;
|
||||
method.visitVarInsn(ASTORE, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadUndefined(final MethodVisitor method) {
|
||||
method.visitFieldInsn(GETSTATIC, className(ScriptRuntime.class), "UNDEFINED", typeDescriptor(Undefined.class));
|
||||
return OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadEmpty(final MethodVisitor method) {
|
||||
method.visitFieldInsn(GETSTATIC, className(ScriptRuntime.class), "EMPTY", typeDescriptor(Undefined.class));
|
||||
return OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type ldc(final MethodVisitor method, final Object c) {
|
||||
if (c == null) {
|
||||
method.visitInsn(ACONST_NULL);
|
||||
} else if (c instanceof Undefined) {
|
||||
return loadUndefined(method);
|
||||
} else if (c instanceof String) {
|
||||
method.visitLdcInsn(c);
|
||||
return STRING;
|
||||
} else if (c instanceof Handle) {
|
||||
method.visitLdcInsn(c);
|
||||
return Type.typeFor(MethodHandle.class);
|
||||
} else {
|
||||
assert false : "implementation missing for class " + c.getClass() + " value=" + c;
|
||||
}
|
||||
|
||||
return OBJECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type convert(final MethodVisitor method, final Type to) {
|
||||
final boolean toString = to.isString();
|
||||
if (!toString) {
|
||||
if (to.isArray()) {
|
||||
final Type elemType = ((ArrayType)to).getElementType();
|
||||
|
||||
//note that if this an array, things won't work. see {link @ArrayType} subclass.
|
||||
//we also have the unpleasant case of NativeArray which looks like an Object, but is
|
||||
//an array to the type system. This is treated specially at the known load points
|
||||
|
||||
if (elemType.isString()) {
|
||||
method.visitTypeInsn(CHECKCAST, CompilerConstants.className(String[].class));
|
||||
} else if (elemType.isNumber()) {
|
||||
method.visitTypeInsn(CHECKCAST, CompilerConstants.className(double[].class));
|
||||
} else if (elemType.isLong()) {
|
||||
method.visitTypeInsn(CHECKCAST, CompilerConstants.className(long[].class));
|
||||
} else if (elemType.isInteger()) {
|
||||
method.visitTypeInsn(CHECKCAST, CompilerConstants.className(int[].class));
|
||||
} else {
|
||||
method.visitTypeInsn(CHECKCAST, CompilerConstants.className(Object[].class));
|
||||
}
|
||||
return to;
|
||||
} else if (to.isObject()) {
|
||||
return to;
|
||||
}
|
||||
} else if (isString()) {
|
||||
return to;
|
||||
}
|
||||
|
||||
if (to.isInteger()) {
|
||||
invokeStatic(method, JSType.TO_INT32);
|
||||
} else if (to.isNumber()) {
|
||||
invokeStatic(method, JSType.TO_NUMBER);
|
||||
} else if (to.isLong()) {
|
||||
invokeStatic(method, JSType.TO_INT64);
|
||||
} else if (to.isBoolean()) {
|
||||
invokeStatic(method, JSType.TO_BOOLEAN);
|
||||
} else if (to.isString()) {
|
||||
invokeStatic(method, JSType.TO_PRIMITIVE);
|
||||
invokeStatic(method, JSType.TO_STRING);
|
||||
} else {
|
||||
assert false : "Illegal conversion " + this + " -> " + to + " " + isString() + " " + toString;
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void _return(final MethodVisitor method) {
|
||||
method.visitInsn(ARETURN);
|
||||
}
|
||||
}
|
||||
882
nashorn/src/jdk/nashorn/internal/codegen/types/Type.java
Normal file
882
nashorn/src/jdk/nashorn/internal/codegen/types/Type.java
Normal file
@ -0,0 +1,882 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.codegen.types;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X1;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X2;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP_X1;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.DUP_X2;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.POP;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.POP2;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.T_DOUBLE;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.T_INT;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
|
||||
|
||||
/**
|
||||
* This is the representation of a JavaScript type, disassociated from java
|
||||
* Classes, with the basis for conversion weight, mapping to ASM types
|
||||
* and implementing the ByteCodeOps interface which tells this type
|
||||
* how to generate code for various operations.
|
||||
*
|
||||
* Except for ClassEmitter, this is the only class that has to know
|
||||
* about the underlying byte code generation system.
|
||||
*
|
||||
* The different types know how to generate bytecode for the different
|
||||
* operations, inherited from BytecodeOps, that they support. This avoids
|
||||
* if/else chains depending on type in several cases and allows for
|
||||
* more readable and shorter code
|
||||
*
|
||||
* The Type class also contains logic used by the type inference and
|
||||
* for comparing types against each other, as well as the concepts
|
||||
* of narrower to wider types. The widest type is an object. Ideally we
|
||||
* would like as narrow types as possible for code to be efficient, e.g
|
||||
* INTs rather than OBJECTs
|
||||
*/
|
||||
|
||||
public abstract class Type implements Comparable<Type>, BytecodeOps {
|
||||
|
||||
/** Human readable name for type */
|
||||
private final String name;
|
||||
|
||||
/** Descriptor for type */
|
||||
private final String descriptor;
|
||||
|
||||
/** The "weight" of the type. Used for picking widest/least specific common type */
|
||||
private final int weight;
|
||||
|
||||
/** How many bytecode slots does this type occupy */
|
||||
private final int slots;
|
||||
|
||||
/** The class for this type */
|
||||
private final Class<?> clazz;
|
||||
|
||||
/** Weights are used to decide which types are "wider" than other types */
|
||||
protected static final int MIN_WEIGHT = -1;
|
||||
|
||||
/** Set way below Integer.MAX_VALUE to prevent overflow when adding weights. Objects are still heaviest. */
|
||||
protected static final int MAX_WEIGHT = 20;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param clazz class for type
|
||||
* @param weight weight - higher is more generic
|
||||
* @param slots how many bytecode slots the type takes up
|
||||
*/
|
||||
Type(final String name, final Class<?> clazz, final int weight, final int slots) {
|
||||
this.name = name;
|
||||
this.clazz = clazz;
|
||||
this.descriptor = Type.getDescriptor(clazz);
|
||||
this.weight = weight;
|
||||
assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight;
|
||||
this.slots = slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an internal descriptor for a type
|
||||
*
|
||||
* @param type the type
|
||||
* @return descriptor string
|
||||
*/
|
||||
public static String getDescriptor(final Class<?> type) {
|
||||
return jdk.internal.org.objectweb.asm.Type.getDescriptor(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the weight of this type - use this e.g. for sorting method descriptors
|
||||
* @return the weight
|
||||
*/
|
||||
public int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Class representing this type
|
||||
* @return the class for this type
|
||||
*/
|
||||
public Class<?> getTypeClass() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* For specialization, return the next, slightly more difficulty, type
|
||||
* to test.
|
||||
*
|
||||
* @return the next Type
|
||||
*/
|
||||
public Type nextWider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the boxed type for this class
|
||||
* @return the boxed version of this type or null if N/A
|
||||
*/
|
||||
public Class<?> getBoxedType() {
|
||||
assert !getTypeClass().isPrimitive();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a method descriptor given a return type and a param array
|
||||
*
|
||||
* @param returnType return type
|
||||
* @param types parameters
|
||||
*
|
||||
* @return a descriptor string
|
||||
*/
|
||||
public static String getMethodDescriptor(final Type returnType, final Type... types) {
|
||||
final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
itypes[i] = types[i].getInternalType();
|
||||
}
|
||||
return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(returnType.getInternalType(), itypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a method descriptor given a return type and a param array
|
||||
*
|
||||
* @param returnType return type
|
||||
* @param types parameters
|
||||
*
|
||||
* @return a descriptor string
|
||||
*/
|
||||
public static String getMethodDescriptor(final Class<?> returnType, final Class<?>... types) {
|
||||
final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
itypes[i] = getInternalType(types[i]);
|
||||
}
|
||||
return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(getInternalType(returnType), itypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for an internal type, package private - do not use
|
||||
* outside code gen
|
||||
*
|
||||
* @param itype internal type
|
||||
* @return Nashorn type
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) {
|
||||
switch (itype.getSort()) {
|
||||
case jdk.internal.org.objectweb.asm.Type.BOOLEAN:
|
||||
return BOOLEAN;
|
||||
case jdk.internal.org.objectweb.asm.Type.INT:
|
||||
return INT;
|
||||
case jdk.internal.org.objectweb.asm.Type.LONG:
|
||||
return LONG;
|
||||
case jdk.internal.org.objectweb.asm.Type.DOUBLE:
|
||||
return NUMBER;
|
||||
case jdk.internal.org.objectweb.asm.Type.OBJECT:
|
||||
return OBJECT;
|
||||
case jdk.internal.org.objectweb.asm.Type.VOID:
|
||||
return null;
|
||||
case jdk.internal.org.objectweb.asm.Type.ARRAY:
|
||||
switch (itype.getElementType().getSort()) {
|
||||
case jdk.internal.org.objectweb.asm.Type.DOUBLE:
|
||||
return NUMBER_ARRAY;
|
||||
case jdk.internal.org.objectweb.asm.Type.INT:
|
||||
return INT_ARRAY;
|
||||
case jdk.internal.org.objectweb.asm.Type.LONG:
|
||||
return LONG_ARRAY;
|
||||
default:
|
||||
assert false;
|
||||
case jdk.internal.org.objectweb.asm.Type.OBJECT:
|
||||
return OBJECT_ARRAY;
|
||||
}
|
||||
|
||||
default:
|
||||
assert false : "Unknown itype : " + itype + " sort " + itype.getSort();
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the return type for a method
|
||||
*
|
||||
* @param methodDescriptor method descriptor
|
||||
* @return return type
|
||||
*/
|
||||
public static Type getMethodReturnType(final String methodDescriptor) {
|
||||
return Type.typeFor(jdk.internal.org.objectweb.asm.Type.getReturnType(methodDescriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type array representing arguments of a method in order
|
||||
*
|
||||
* @param methodDescriptor method descriptor
|
||||
* @return parameter type array
|
||||
*/
|
||||
public static Type[] getMethodArguments(final String methodDescriptor) {
|
||||
final jdk.internal.org.objectweb.asm.Type itypes[] = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodDescriptor);
|
||||
final Type types[] = new Type[itypes.length];
|
||||
for (int i = 0; i < itypes.length; i++) {
|
||||
types[i] = Type.typeFor(itypes[i]);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
static jdk.internal.org.objectweb.asm.Type getInternalType(final String className) {
|
||||
return jdk.internal.org.objectweb.asm.Type.getType(className);
|
||||
}
|
||||
|
||||
private jdk.internal.org.objectweb.asm.Type getInternalType() {
|
||||
return jdk.internal.org.objectweb.asm.Type.getType(getTypeClass());
|
||||
}
|
||||
|
||||
private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) {
|
||||
return jdk.internal.org.objectweb.asm.Type.getType(type);
|
||||
}
|
||||
|
||||
static void invokeStatic(final MethodVisitor method, final Call call) {
|
||||
method.visitMethodInsn(INVOKESTATIC, call.className(), call.name(), call.descriptor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal JVM name of a type
|
||||
* @return the internal name
|
||||
*/
|
||||
public String getInternalName() {
|
||||
return jdk.internal.org.objectweb.asm.Type.getInternalName(getTypeClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal JVM name of type type represented by a given Java class
|
||||
* @param clazz the class
|
||||
* @return the internal name
|
||||
*/
|
||||
public static String getInternalName(final Class<?> clazz) {
|
||||
return jdk.internal.org.objectweb.asm.Type.getInternalName(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is the UNKNOWN type, i.e. not set yet
|
||||
* Used for type inference.
|
||||
*
|
||||
* @return true if UNKNOWN, false otherwise
|
||||
*/
|
||||
public boolean isUnknown() {
|
||||
return this.equals(Type.UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is the BOOLEAN type
|
||||
* @return true if BOOLEAN, false otherwise
|
||||
*/
|
||||
public boolean isBoolean() {
|
||||
return this.equals(Type.BOOLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is the INT type
|
||||
* @return true if INTEGER, false otherwise
|
||||
*/
|
||||
public boolean isInteger() {
|
||||
return this.equals(Type.INT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is the LONG type
|
||||
* @return true if LONG, false otherwise
|
||||
*/
|
||||
public boolean isLong() {
|
||||
return this.equals(Type.LONG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is the NUMBER type
|
||||
* @return true if NUMBER, false otherwise
|
||||
*/
|
||||
public boolean isNumber() {
|
||||
return this.equals(Type.NUMBER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is numeric, i.e. NUMBER,
|
||||
* INT, LONG.
|
||||
*
|
||||
* @return true if numeric, false otherwise
|
||||
*/
|
||||
public boolean isNumeric() {
|
||||
return this instanceof NumericType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is an array type, i.e.
|
||||
* OBJECT_ARRAY or NUMBER_ARRAY (for now)
|
||||
*
|
||||
* @return true if an array type, false otherwise
|
||||
*/
|
||||
public boolean isArray() {
|
||||
return this instanceof ArrayType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a type takes up two bytecode slots or not
|
||||
*
|
||||
* @return true if type takes up two bytecode slots rather than one
|
||||
*/
|
||||
public boolean isCategory2() {
|
||||
return getSlots() == 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is an OBJECT type, e.g. OBJECT, STRING,
|
||||
* NUMBER_ARRAY etc.
|
||||
*
|
||||
* @return true if object type, false otherwise
|
||||
*/
|
||||
public boolean isObject() {
|
||||
return this instanceof ObjectType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a type is a STRING type
|
||||
*
|
||||
* @return true if object type, false otherwise
|
||||
*/
|
||||
public boolean isString() {
|
||||
return this.equals(Type.STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if two types are equivalent, i.e. need no conversion
|
||||
*
|
||||
* @param type the second type to check
|
||||
*
|
||||
* @return true if types are equivalent, false otherwise
|
||||
*/
|
||||
public boolean isEquivalentTo(final Type type) {
|
||||
return this.weight() == type.weight() || (isObject() && type.isObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a type can be assigned to from another
|
||||
*
|
||||
* @param type0 the first type to check
|
||||
* @param type1 the second type to check
|
||||
*
|
||||
* @return true if type1 can be written to type2, false otherwise
|
||||
*/
|
||||
public static boolean isAssignableFrom(final Type type0, final Type type1) {
|
||||
if (type0.isObject() && type1.isObject()) {
|
||||
return type0.weight() >= type1.weight();
|
||||
}
|
||||
|
||||
return type0.weight() == type1.weight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this type is assignable from another type
|
||||
* @param type the type to check against
|
||||
*
|
||||
* @return true if "type" can be written to this type, false otherwise
|
||||
*/
|
||||
public boolean isAssignableFrom(final Type type) {
|
||||
return Type.isAssignableFrom(this, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines is this type is equivalent to another, i.e. needs no conversion
|
||||
* to be assigned to it.
|
||||
*
|
||||
* @param type0 the first type to check
|
||||
* @param type1 the second type to check
|
||||
*
|
||||
* @return true if this type is equivalent to type, false otherwise
|
||||
*/
|
||||
public static boolean areEquivalent(final Type type0, final Type type1) {
|
||||
return type0.isEquivalentTo(type1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the number of bytecode slots a type takes up
|
||||
*
|
||||
* @return the number of slots for this type, 1 or 2.
|
||||
*/
|
||||
public int getSlots() {
|
||||
return slots;
|
||||
}
|
||||
/**
|
||||
* Returns the widest or most common of two types
|
||||
*
|
||||
* @param type0 type one
|
||||
* @param type1 type two
|
||||
*
|
||||
* @return the widest type
|
||||
*/
|
||||
public static Type widest(final Type type0, final Type type1) {
|
||||
if (type0.isArray() && type1.isArray()) {
|
||||
return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT;
|
||||
} else if (type0.isArray() != type1.isArray()) {
|
||||
return Type.OBJECT; //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense
|
||||
}
|
||||
return type0.weight() > type1.weight() ? type0 : type1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the narrowest or least common of two types
|
||||
*
|
||||
* @param type0 type one
|
||||
* @param type1 type two
|
||||
*
|
||||
* @return the widest type
|
||||
*/
|
||||
public static Type narrowest(final Type type0, final Type type1) {
|
||||
return type0.weight() < type1.weight() ? type0 : type1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the widest or most common of two types, but no wider than "limit"
|
||||
*
|
||||
* @param type0 type one
|
||||
* @param type1 type two
|
||||
* @param limit limiting type
|
||||
*
|
||||
* @return the widest type, but no wider than limit
|
||||
*/
|
||||
public static Type widest(final Type type0, final Type type1, final Type limit) {
|
||||
final Type type = Type.widest(type0, type1);
|
||||
if (type.weight() > limit.weight()) {
|
||||
return limit;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the widest or most common of two types, but no narrower than "limit"
|
||||
*
|
||||
* @param type0 type one
|
||||
* @param type1 type two
|
||||
* @param limit limiting type
|
||||
*
|
||||
* @return the widest type, but no wider than limit
|
||||
*/
|
||||
public static Type narrowest(final Type type0, final Type type1, final Type limit) {
|
||||
final Type type = type0.weight() < type1.weight() ? type0 : type1;
|
||||
if (type.weight() < limit.weight()) {
|
||||
return limit;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the narrowest of this type and another
|
||||
*
|
||||
* @param other type to compare against
|
||||
*
|
||||
* @return the widest type
|
||||
*/
|
||||
public Type narrowest(final Type other) {
|
||||
return Type.narrowest(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the widest of this type and another
|
||||
*
|
||||
* @param other type to compare against
|
||||
*
|
||||
* @return the widest type
|
||||
*/
|
||||
public Type widest(final Type other) {
|
||||
return Type.widest(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the weight of a type, used for type comparison
|
||||
* between wider and narrower types
|
||||
*
|
||||
* @return the weight
|
||||
*/
|
||||
int weight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the descriptor of a type, used for e.g. signature
|
||||
* generation
|
||||
*
|
||||
* @return the descriptor
|
||||
*/
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the (possibly cached) Type object for this class
|
||||
*
|
||||
* @param clazz the class to check
|
||||
*
|
||||
* @return the Type representing this class
|
||||
*/
|
||||
public static Type typeFor(final Class<?> clazz) {
|
||||
Type type = cache.get(clazz);
|
||||
|
||||
if (type == null) {
|
||||
assert !clazz.isPrimitive() || clazz == void.class;
|
||||
if (clazz.isArray()) {
|
||||
type = new ArrayType(clazz);
|
||||
} else {
|
||||
type = new ObjectType(clazz);
|
||||
}
|
||||
cache.put(clazz, type);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Type o) {
|
||||
return o.weight() - weight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Common logic for implementing dup for all types
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param depth dup depth
|
||||
*
|
||||
* @return the type at the top of the stack afterwards
|
||||
*/
|
||||
@Override
|
||||
public Type dup(final MethodVisitor method, final int depth) {
|
||||
return Type.dup(method, this, depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Common logic for implementing swap for all types
|
||||
*
|
||||
* @param method method visitor
|
||||
* @param other the type to swap with
|
||||
*
|
||||
* @return the type at the top of the stack afterwards, i.e. other
|
||||
*/
|
||||
@Override
|
||||
public Type swap(final MethodVisitor method, final Type other) {
|
||||
Type.swap(method, this, other);
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common logic for implementing pop for all types
|
||||
*
|
||||
* @param method method visitor
|
||||
*
|
||||
* @return the type that was popped
|
||||
*/
|
||||
@Override
|
||||
public Type pop(final MethodVisitor method) {
|
||||
Type.pop(method, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Superclass logic for pop for all types
|
||||
*
|
||||
* @param method method emitter
|
||||
* @param type type to pop
|
||||
*/
|
||||
protected static void pop(final MethodVisitor method, final Type type) {
|
||||
method.visitInsn(type.isCategory2() ? POP2 : POP);
|
||||
}
|
||||
|
||||
private static Type dup(final MethodVisitor method, final Type type, final int depth) {
|
||||
final boolean cat2 = type.isCategory2();
|
||||
|
||||
switch (depth) {
|
||||
case 0:
|
||||
method.visitInsn(cat2 ? DUP2 : DUP);
|
||||
break;
|
||||
case 1:
|
||||
method.visitInsn(cat2 ? DUP2_X1 : DUP_X1);
|
||||
break;
|
||||
case 2:
|
||||
method.visitInsn(cat2 ? DUP2_X2 : DUP_X2);
|
||||
break;
|
||||
default:
|
||||
return null; //invalid depth
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private static void swap(final MethodVisitor method, final Type above, final Type below) {
|
||||
final MethodVisitor mv = method;
|
||||
if (below.isCategory2()) {
|
||||
if (above.isCategory2()) {
|
||||
mv.visitInsn(DUP2_X2);
|
||||
mv.visitInsn(POP2);
|
||||
} else {
|
||||
mv.visitInsn(DUP_X2);
|
||||
mv.visitInsn(POP);
|
||||
}
|
||||
} else {
|
||||
if (above.isCategory2()) {
|
||||
mv.visitInsn(DUP2_X1);
|
||||
mv.visitInsn(POP2);
|
||||
} else {
|
||||
mv.visitInsn(SWAP);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the boolean singleton, used for all boolean types
|
||||
*/
|
||||
public static final Type BOOLEAN = new BooleanType();
|
||||
|
||||
/**
|
||||
* This is an integer type, i.e INT, INT32.
|
||||
*/
|
||||
public static final Type INT = new IntType();
|
||||
|
||||
/**
|
||||
* This is the number singleton, used for all number types
|
||||
*/
|
||||
public static final Type NUMBER = new NumberType();
|
||||
|
||||
/**
|
||||
* This is the long singleton, used for all long types
|
||||
*/
|
||||
public static final Type LONG = new LongType();
|
||||
|
||||
/**
|
||||
* A string singleton
|
||||
*/
|
||||
public static final Type STRING = new ObjectType(String.class);
|
||||
|
||||
/**
|
||||
* This is the object singleton, used for all object types
|
||||
*/
|
||||
public static final Type OBJECT = new ObjectType();
|
||||
|
||||
/**
|
||||
* This is the singleton for integer arrays
|
||||
*/
|
||||
public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
|
||||
@Override
|
||||
public void astore(final MethodVisitor method) {
|
||||
method.visitInsn(IASTORE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type aload(final MethodVisitor method) {
|
||||
method.visitInsn(IALOAD);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type newarray(final MethodVisitor method) {
|
||||
method.visitIntInsn(NEWARRAY, T_INT);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getElementType() {
|
||||
return INT;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the singleton for long arrays
|
||||
*/
|
||||
public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
|
||||
@Override
|
||||
public void astore(final MethodVisitor method) {
|
||||
method.visitInsn(LASTORE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type aload(final MethodVisitor method) {
|
||||
method.visitInsn(IALOAD);
|
||||
return INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type newarray(final MethodVisitor method) {
|
||||
method.visitIntInsn(NEWARRAY, T_INT);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getElementType() {
|
||||
return INT;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the singleton for numeric arrays
|
||||
*/
|
||||
public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
|
||||
@Override
|
||||
public void astore(final MethodVisitor method) {
|
||||
method.visitInsn(DASTORE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type aload(final MethodVisitor method) {
|
||||
method.visitInsn(DALOAD);
|
||||
return NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type newarray(final MethodVisitor method) {
|
||||
method.visitIntInsn(NEWARRAY, T_DOUBLE);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getElementType() {
|
||||
return NUMBER;
|
||||
}
|
||||
};
|
||||
|
||||
/** Singleton for method handle arrays used for properties etc. */
|
||||
public static final ArrayType METHODHANDLE_ARRAY = new ArrayType(new MethodHandle[0].getClass());
|
||||
|
||||
/** This is the singleton for string arrays */
|
||||
public static final ArrayType STRING_ARRAY = new ArrayType(new String[0].getClass());
|
||||
|
||||
/** This is the singleton for object arrays */
|
||||
public static final ArrayType OBJECT_ARRAY = new ArrayType(new Object[0].getClass());
|
||||
|
||||
/** This type, always an object type, just a toString override */
|
||||
public static final Type THIS = new ObjectType() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "this";
|
||||
}
|
||||
};
|
||||
|
||||
/** Scope type, always an object type, just a toString override */
|
||||
public static final Type SCOPE = new ObjectType() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "scope";
|
||||
}
|
||||
};
|
||||
|
||||
private static interface Unknown {
|
||||
// EMPTY - used as a class that is absolutely not compatible with a type to represent "unknown"
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the unknown type which is used as initial type for type
|
||||
* inference. It has the minimum type width
|
||||
*/
|
||||
public static final Type UNKNOWN = new Type("<unknown>", Unknown.class, MIN_WEIGHT, 1) {
|
||||
|
||||
@Override
|
||||
public String getDescriptor() {
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type load(final MethodVisitor method, final int slot) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(final MethodVisitor method, final int slot) {
|
||||
assert false : "unsupported operation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type ldc(final MethodVisitor method, final Object c) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadUndefined(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type loadEmpty(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type convert(final MethodVisitor method, final Type to) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void _return(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type add(final MethodVisitor method) {
|
||||
assert false : "unsupported operation";
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/** Mappings between java classes and their Type singletons */
|
||||
private static final Map<Class<?>, Type> cache = Collections.synchronizedMap(new HashMap<Class<?>, Type>());
|
||||
|
||||
//TODO may need to be cleared, as all types are retained throughout code generation
|
||||
static {
|
||||
cache.put(BOOLEAN.getTypeClass(), BOOLEAN);
|
||||
cache.put(INT.getTypeClass(), INT);
|
||||
cache.put(LONG.getTypeClass(), LONG);
|
||||
cache.put(NUMBER.getTypeClass(), NUMBER);
|
||||
cache.put(STRING.getTypeClass(), STRING);
|
||||
cache.put(OBJECT.getTypeClass(), OBJECT);
|
||||
cache.put(OBJECT_ARRAY.getTypeClass(), OBJECT_ARRAY);
|
||||
}
|
||||
|
||||
}
|
||||
166
nashorn/src/jdk/nashorn/internal/ir/AccessNode.java
Normal file
166
nashorn/src/jdk/nashorn/internal/ir/AccessNode.java
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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. 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.nashorn.internal.ir;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.DEBUG_FIELDS;
|
||||
|
||||
import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of a property access (period operator.)
|
||||
*
|
||||
*/
|
||||
public class AccessNode extends BaseNode implements TypeOverride {
|
||||
/** Property ident. */
|
||||
private IdentNode property;
|
||||
|
||||
/** Does this node have a type override */
|
||||
private boolean hasCallSiteType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param base base node
|
||||
* @param property property
|
||||
*/
|
||||
public AccessNode(final Source source, final long token, final int finish, final Node base, final IdentNode property) {
|
||||
super(source, token, finish, base);
|
||||
|
||||
this.start = base.getStart();
|
||||
this.property = property;
|
||||
|
||||
this.property.setIsPropertyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*
|
||||
* @param accessNode source node
|
||||
*/
|
||||
public AccessNode(final AccessNode accessNode) {
|
||||
this(accessNode, new CopyState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal copy constructor
|
||||
*
|
||||
* @param accessNode source node
|
||||
* @param cs copy state
|
||||
*/
|
||||
protected AccessNode(final AccessNode accessNode, final CopyState cs) {
|
||||
super(accessNode, cs);
|
||||
this.property = (IdentNode)cs.existingOrCopy(accessNode.getProperty());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node copy(final CopyState cs) {
|
||||
return new AccessNode(this, cs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (!super.equals(other)) {
|
||||
return false;
|
||||
}
|
||||
final AccessNode accessNode = (AccessNode)other;
|
||||
return property.equals(accessNode.getProperty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode() ^ property.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assist in IR navigation.
|
||||
* @param visitor IR navigating visitor.
|
||||
*/
|
||||
@Override
|
||||
public Node accept(final NodeVisitor visitor) {
|
||||
if (visitor.enter(this) != null) {
|
||||
base = base.accept(visitor);
|
||||
property = (IdentNode)property.accept(visitor);
|
||||
return visitor.leave(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toString(final StringBuilder sb) {
|
||||
final boolean needsParen = tokenType().needsParens(getBase().tokenType(), true);
|
||||
|
||||
if (hasCallSiteType) {
|
||||
sb.append('{');
|
||||
final String desc = getType().getDescriptor();
|
||||
sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
|
||||
sb.append('}');
|
||||
}
|
||||
|
||||
if (needsParen) {
|
||||
sb.append('(');
|
||||
}
|
||||
|
||||
base.toString(sb);
|
||||
|
||||
if (needsParen) {
|
||||
sb.append(')');
|
||||
}
|
||||
sb.append('.');
|
||||
|
||||
sb.append(property.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the property
|
||||
*
|
||||
* @return the property IdentNode
|
||||
*/
|
||||
public IdentNode getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(final Type type) {
|
||||
if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
|
||||
ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
|
||||
}
|
||||
property.setType(type);
|
||||
getSymbol().setTypeOverride(type); //always a temp so this is fine.
|
||||
hasCallSiteType = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHaveCallSiteType() {
|
||||
return true; //carried by the symbol and always the same nodetype==symboltype
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user