pax_global_header00006660000000000000000000000064124704742440014522gustar00rootroot0000000000000052 comment=8fbf5ed5535faf226357db6b982f18288859f140 jffi-1.2.7/000077500000000000000000000000001247047424400124475ustar00rootroot00000000000000jffi-1.2.7/.classpath000066400000000000000000000006051247047424400144330ustar00rootroot00000000000000 jffi-1.2.7/.gitignore000066400000000000000000000002171247047424400144370ustar00rootroot00000000000000*.orig$ *.rej$ *~ nbproject/private build build.eclipse dist lib/nblibraries-private.properties jni/libffi/doc/libffi.info$ /.settings/ target jffi-1.2.7/.hgignore000066400000000000000000000002311247047424400142460ustar00rootroot00000000000000\.orig$ \.orig\..*$ \.chg\..*$ \.rej$ \.conflict\~$ ^nbproject/private ^build/.*$ ^dist ^lib/nblibraries-private.properties ^jni/libffi/doc/libffi.info$ jffi-1.2.7/.project000066400000000000000000000010561247047424400141200ustar00rootroot00000000000000 jffi org.eclipse.jdt.core.javabuilder org.maven.ide.eclipse.maven2Builder org.maven.ide.eclipse.maven2Nature org.eclipse.jdt.core.javanature jffi-1.2.7/.settings/000077500000000000000000000000001247047424400143655ustar00rootroot00000000000000jffi-1.2.7/.settings/org.eclipse.jdt.core.prefs000066400000000000000000000004221247047424400213450ustar00rootroot00000000000000#Wed Dec 30 13:18:41 CET 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.source=1.5 jffi-1.2.7/.settings/org.maven.ide.eclipse.prefs000066400000000000000000000004201247047424400215010ustar00rootroot00000000000000#Wed Dec 30 15:17:24 CET 2009 activeProfiles= eclipse.preferences.version=1 fullBuildGoals=process-test-resources includeModules=false resolveWorkspaceProjects=false resourceFilterGoals=process-resources resources\:testResources skipCompilerPlugin=true version=1 jffi-1.2.7/.travis.yml000066400000000000000000000001021247047424400145510ustar00rootroot00000000000000language: java jdk: - oraclejdk7 - openjdk6 script: ant test jffi-1.2.7/COPYING.GPL000066400000000000000000001045131247047424400141270ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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 Lesser General Public License instead of this License. But first, please read . jffi-1.2.7/COPYING.LESSER000066400000000000000000000167271247047424400145130ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. jffi-1.2.7/LICENSE000066400000000000000000000022601247047424400134540ustar00rootroot00000000000000 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Alternatively, you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License version 3 for more details. You should have received a copy of the GNU Lesser General Public License version 3 along with this work. If not, see . jffi-1.2.7/build.xml000066400000000000000000000337231247047424400143000ustar00rootroot00000000000000 Builds, tests, and runs the project jffi. jffi-1.2.7/jni/000077500000000000000000000000001247047424400132275ustar00rootroot00000000000000jffi-1.2.7/jni/GNUmakefile000077500000000000000000000237371247047424400153200ustar00rootroot00000000000000# -*- makefile -*- BUILD_OS := $(strip $(shell uname -s | tr '[:upper:]' '[:lower:]')) OS ?= $(BUILD_OS) ifeq ($(OS),sunos) OS = solaris endif # Default value of $OS on Windows is Windows_NT ifeq ($(OS), Windows_NT) # that's how we detect x64... ifneq ($(findstring 64, $(BUILD_OS)),) OS = win64 else OS = win32 endif endif ifneq ($(findstring cygwin, $(BUILD_OS)),) # cygwin is always x32 OS = win32 endif CPU ?= $(shell uname -m | sed -e 's/i[345678]86/i386/') MODEL = 32 # Default to 32bit compiles PLATFORM = $(CPU)-$(OS) JDK_HOME=$(shell if [ -d "$(JAVA_HOME)"/include ];then echo "$(JAVA_HOME)"; else echo "$(JAVA_HOME)"/..; fi) # Set defaults to unix (linux/solaris/bsd) PREFIX = lib JNIEXT = so export MACOSX_DEPLOYMENT_TARGET=10.4 CCACHE := $(strip $(realpath $(shell which ccache 2> /dev/null))) SRC_DIR ?= $(shell pwd)/jni JNI_DIR ?= $(SRC_DIR) BUILD_DIR ?= $(shell pwd)/build JFFI_SRC_DIR = $(SRC_DIR)/jffi JFFI_BUILD_DIR = $(BUILD_DIR)/jffi ifeq ($(USE_SYSTEM_LIBFFI),1) LIBFFI_LIBS ?= $(shell pkg-config --libs libffi) LIBFFI_CFLAGS ?= $(shell pkg-config --cflags libffi) else LIBFFI_SRC_DIR = $(SRC_DIR)/libffi LIBFFI_BUILD_DIR = $(BUILD_DIR)/libffi-$(PLATFORM) LIBFFI = $(LIBFFI_BUILD_DIR)/.libs/libffi_convenience.a LIBFFI_LIBS = $(LIBFFI) LIBFFI_CFLAGS = -I"$(LIBFFI_BUILD_DIR)"/include endif SRCS = $(wildcard $(JFFI_SRC_DIR)/*.c) OBJS = $(patsubst %.c, $(JFFI_BUILD_DIR)/%.o, $(notdir $(SRCS))) vpath %.h $(JFFI_SRC_DIR) LIBNAME = jffi # # Compiler/linker flags from: # http://weblogs.java.net/blog/kellyohair/archive/2006/01/compilation_of_1.html JFLAGS = -fno-omit-frame-pointer -fno-strict-aliasing -DNDEBUG OFLAGS = -O2 $(JFLAGS) # MacOS headers aren't completely warning free, so turn them off WERROR = -Werror ifneq ($(OS),darwin) WFLAGS += -Wundef $(WERROR) endif WFLAGS += -W -Wall -Wno-unused -Wno-parentheses PICFLAGS = -fPIC SOFLAGS = # Filled in for each OS specifically FFI_MMAP_EXEC = -DFFI_MMAP_EXEC_WRIT FFI_CC = $(CCACHE) $(CC) FFI_LD = $(LD) FFI_CFLAGS = $(FFI_MMAP_EXEC) $(OFLAGS) STRIP ?= strip -S JDK_INCLUDES = -I"$(JDK_HOME)/include" -I"$(JDK_HOME)/include/$(OS)" IFLAGS = -I"$(BUILD_DIR)" -I"$(BUILD_DIR)"/jni -I$(SRC_DIR) -I"$(JFFI_SRC_DIR)" CFLAGS += $(OFLAGS) $(WFLAGS) $(IFLAGS) $(PICFLAGS) $(JDK_INCLUDES) $(LIBFFI_CFLAGS) CFLAGS += -D_REENTRANT -D_LARGEFILE64_SOURCE -D_GNU_SOURCE ifeq ($(OS), win64) override CPU = x86_64 JDK_INCLUDES=-I$(JNI_DIR)/win32/include -I$(JNI_DIR)/win32/include/win32 CC = x86_64-w64-mingw32-gcc -m64 PICFLAGS = ifneq ($(findstring cygwin, $(BUILD_OS)),) CC += -mno-cygwin LDFLAGS += -mno-cygwin endif CFLAGS += -mwin32 -D_JNI_IMPLEMENTATION_ LDFLAGS += -Wl,--add-stdcall-alias PICFLAGS= SOFLAGS += -shared -static-libgcc PREFIX = JNIEXT=dll AR = x86_64-w64-mingw32-ar LD = x86_64-w64-mingw32-ld STRIP = x86_64-w64-mingw32-strip --strip-debug CONFIGURE_BUILD = x86_64-w64-mingw32 endif ifeq ($(OS),cross-mingw32) override OS = win32 override CPU = i386 JDK_INCLUDES=-I$(JNI_DIR)/win32/include -I$(JNI_DIR)/win32/include/win32 CC = i686-w64-mingw32-gcc LD = i686-w64-mingw32-ld STRIP = i686-w64-mingw32-strip --strip-debug export RANLIB = i686-w64-mingw32-ranlib CONFIGURE_HOST = i686-mingw32 CROSS_COMPILE=1 endif ifeq ($(OS),cross-win64) override CPU = x86_64 override OS = win64 JDK_INCLUDES=-I$(JNI_DIR)/win32/include -I$(JNI_DIR)/win32/include/win32 CC = x86_64-w64-mingw32-gcc LD = x86_64-w64-mingw32-ld STRIP = x86_64-w64-mingw32-strip --strip-debug AR = x86_64-w64-mingw32-ar LD = x86_64-w64-mingw32-ld export RANLIB = x86_64-w64-mingw32-ranlib CONFIGURE_HOST = x86_64-w64-mingw32 PICFLAGS = CROSS_COMPILE=1 SOFLAGS += -shared -static-libgcc PREFIX = JNIEXT=dll endif ifneq ($(findstring cygwin,$(BUILD_OS)),) OS = win32 JAVA_HOME := $(shell cygpath -u $(JAVA_HOME)) endif ifeq ($(OS), win32) ifneq ($(findstring cygwin, $(BUILD_OS)),) CC += -mno-cygwin LDFLAGS += -mno-cygwin endif CFLAGS += -mwin32 -D_JNI_IMPLEMENTATION_ # Linking against CRTMT.O is a workaround for GCC 4.4 bug # that ignores __thread (which we really need for errno handling). # See: http://n2.nabble.com/gcc-4-4-multi-threaded-exception-handling-thread-specifier-not-working-td3440749.html ifeq ($(findstring -w64-,$(CC)),) CRTMT.O = $(shell $(CC) -print-file-name=crtmt.o) endif LDFLAGS += -Wl,--add-stdcall-alias $(CRTMT.O) PICFLAGS= SOFLAGS += -shared -static-libgcc PREFIX = JNIEXT=dll endif ifeq ($(OS), darwin) PLATFORM = darwin ARCHES = ifneq ($(findstring $(CPU), ppc powerpc),) ARCHES += ppc endif ifneq ($(findstring $(CPU), i386 x86_64),) ARCHES += i386 x86_64 endif ifneq ($(realpath $(wildcard /Xcode3/usr/bin/gcc)),) XCODE=/Xcode3 else XCODE=$(shell xcode-select -print-path) endif ifneq ($(realpath $(wildcard $(XCODE)/usr/bin/gcc-4.0)),) CC = $(XCODE)/usr/bin/gcc-4.0 else CC = $(XCODE)/usr/bin/gcc endif UNIVERSAL_SDK = $(firstword $(strip $(realpath $(XCODE)/SDKs/MacOSX10.4u.sdk) $(realpath $(XCODE)/SDKs/MacOSX10.5.sdk))) ifneq ($(UNIVERSAL_SDK),) MACSDK = $(UNIVERSAL_SDK) ifeq ($(findstring ppc, $(ARCHES)),) ARCHES += ppc endif else MACSDK = $(firstword $(strip $(wildcard $(XCODE)/SDKs/MacOSX10.*.sdk)) $(strip $(wildcard $(XCODE)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.*.sdk))) endif CFLAGS += -isysroot $(MACSDK) -DTARGET_RT_MAC_CFM=0 CFLAGS += -I$(MACSDK)/System/Library/Frameworks/JavaVM.framework/Headers CFLAGS += $(foreach arch, $(ARCHES),-arch $(arch)) LDFLAGS = $(foreach arch, $(ARCHES),-arch $(arch)) -dynamiclib -framework JavaVM \ -Wl,-syslibroot,$(MACSDK) -mmacosx-version-min=10.6 JNIEXT = jnilib #CFLAGS += -I$(MACSDK)/System/Library/Frameworks/Kernel.framework/Versions/A/Headers CFLAGS += -fexceptions FFI_CFLAGS += -isysroot $(MACSDK) -I$(MACSDK)/usr/include PICFLAGS = SOFLAGS = #LIBS += $(JAVA_HOME)/jre/lib/libjsig.dylib OBJS += $(JFFI_BUILD_DIR)/darwin-longjmp.o $(JFFI_BUILD_DIR)/darwin-trampoline.o endif ifeq ($(OS), linux) SOFLAGS = -shared -static-libgcc -Wl,-soname,$(@F) -Wl,-O1 CFLAGS += -pthread endif ifeq ($(OS), solaris) CC = gcc CFLAGS += -D__EXTENSIONS__ -std=c99 LD = /usr/ccs/bin/ld SOFLAGS = -shared -static-libgcc LIBS += -ldl STRIP = strip endif ifeq ($(OS), aix) SOFLAGS = -shared -static-libgcc CFLAGS += -pthread LDFLAGS += -pthread JNIEXT = a STRIP = strip endif ifneq ($(findstring bsd, $(OS)),) SOFLAGS = -shared -static-libgcc CFLAGS += -pthread LDFLAGS += -pthread endif ifeq ($(CPU), i386) ifneq ($(findstring $(OS), linux),) CFLAGS += -march=i586 -mtune=generic endif endif ifeq ($(CPU), sparcv9) MODEL=64 endif ifneq ($(findstring $(CPU), x86_64 amd64 ppc64 powerpc64 s390x),) MODEL = 64 endif # On platforms (linux, solaris) that support both 32bit and 64bit, force building for one or the other ifneq ($(strip $(findstring $(OS), solaris linux)),) # Change the CC/LD instead of CFLAGS/LDFLAGS, incase other things in the flags # makes the libffi build choke CC += -m$(MODEL) LD += -m$(MODEL) endif LIBJFFI = $(BUILD_DIR)/$(PREFIX)$(LIBNAME)-$(VERSION).$(JNIEXT) LIBFFI_CONFIGURE = $(LIBFFI_SRC_DIR)/configure --disable-static \ --with-pic=yes --disable-dependency-tracking ifdef CONFIGURE_HOST LIBFFI_CONFIGURE += --host=$(CONFIGURE_HOST) endif ifdef CONFIGURE_BUILD LIBFFI_CONFIGURE += --build=$(CONFIGURE_BUILD) endif all: $(LIBJFFI) debug: @echo OS="$(OS)" @echo BUILD_OS="$(BUILD_OS)" @echo CPU="$(CPU)" @echo JAVA_HOME="$(JAVA_HOME)" @echo JDK_HOME="$(JDK_HOME)" @echo "PLATFORM=$(PLATFORM)" @echo "JFFI_BUILD_DIR=$(JFFI_BUILD_DIR)" @echo "OBJS=$(OBJS)" $(LIBJFFI): $(OBJS) $(LIBFFI_LIBS) $(CC) -o $@ $(LDFLAGS) $(SOFLAGS) $(OBJS) $(LIBFFI_LIBS) $(LIBS) $(STRIP) $@ $(BUILD_DIR)/%.o : $(SRC_DIR)/%.c $(wildcard $(JFFI_SRC_DIR)/*.h) @mkdir -p $(@D) @$(CCACHE) $(CC) $(CFLAGS) -c $< -o $@ $(BUILD_DIR)/%.o : $(SRC_DIR)/%.S $(wildcard $(JFFI_SRC_DIR)/*.h) @mkdir -p $(@D) @$(CC) $(CFLAGS) -o $@ -c $< $(OBJS) : $(LIBFFI_LIBS) ifeq ($(OS), darwin) build_ffi = \ mkdir -p $(BUILD_DIR)/libffi-darwin-$(1); \ (if [ ! -f $(BUILD_DIR)/libffi-darwin-$(1)/Makefile ]; then \ echo "Configuring libffi for $(1)"; \ cd $(BUILD_DIR)/libffi-darwin-$(1) && \ env CC="$(CCACHE) $(CC)" CFLAGS="-arch $(1) $(FFI_CFLAGS)" LDFLAGS="-arch $(1)" \ $(LIBFFI_CONFIGURE) --host=$(1)-apple-darwin > /dev/null; \ fi); \ env MACOSX_DEPLOYMENT_TARGET=10.4 $(MAKE) -C $(BUILD_DIR)/libffi-darwin-$(1) $(LIBFFI): @mkdir -p $(@D) @for arch in $(ARCHES); do $(call build_ffi,$$arch);done # Assemble into a FAT (i386, x86_64, ppc) library @mkdir -p $(BUILD_DIR)/libffi/.libs @env MACOSX_DEPLOYMENT_TARGET=10.4 /usr/bin/libtool -static -o $@ \ $(foreach arch, $(ARCHES),$(BUILD_DIR)/libffi-darwin-$(arch)/.libs/libffi_convenience.a) @mkdir -p $(LIBFFI_BUILD_DIR)/include $(RM) $(LIBFFI_BUILD_DIR)/include/ffi.h @( \ printf "#if defined(__i386__)\n"; \ printf "#include \"libffi-darwin-i386/include/ffi.h\"\n"; \ printf "#elif defined(__x86_64__)\n"; \ printf "#include \"libffi-darwin-x86_64/include/ffi.h\"\n";\ printf "#elif defined(__ppc__)\n"; \ printf "#include \"libffi-darwin-ppc/include/ffi.h\"\n";\ printf "#endif\n";\ ) > $(LIBFFI_BUILD_DIR)/include/ffi.h @( \ printf "#if defined(__i386__)\n"; \ printf "#include \"libffi-darwin-i386/include/ffitarget.h\"\n"; \ printf "#elif defined(__x86_64__)\n"; \ printf "#include \"libffi-darwin-x86_64/include/ffitarget.h\"\n";\ printf "#elif defined(__ppc__)\n"; \ printf "#include \"libffi-darwin-ppc/include/ffitarget.h\"\n";\ printf "#endif\n";\ ) > $(LIBFFI_BUILD_DIR)/include/ffitarget.h else $(LIBFFI): @mkdir -p $(LIBFFI_BUILD_DIR) @if [ ! -f $(LIBFFI_BUILD_DIR)/Makefile ]; then \ echo "Configuring libffi for $(PLATFORM)"; \ cd $(LIBFFI_BUILD_DIR) && env CC="$(FFI_CC)" LD="$(FFI_LD)" CFLAGS="$(FFI_CFLAGS)" \ $(LIBFFI_CONFIGURE) > /dev/null; \ fi $(MAKE) -C $(LIBFFI_BUILD_DIR) endif clean:: # nothing to do - ant will delete the build dir jffi-1.2.7/jni/jffi/000077500000000000000000000000001247047424400141455ustar00rootroot00000000000000jffi-1.2.7/jni/jffi/Array.c000066400000000000000000000227701247047424400153770ustar00rootroot00000000000000/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include #include #include "jffi.h" #include "Exception.h" #include "com_kenai_jffi_ObjectBuffer.h" #include "Array.h" #define ARGPRIM_MASK com_kenai_jffi_ObjectBuffer_PRIM_MASK #define ARGTYPE_MASK com_kenai_jffi_ObjectBuffer_TYPE_MASK #define ARGTYPE_SHIFT com_kenai_jffi_ObjectBuffer_TYPE_SHIFT #define ARGFLAGS_MASK com_kenai_jffi_ObjectBuffer_FLAGS_MASK static void releaseHeapArray(JNIEnv* env, Array* array) { free(array->elems); } #define COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array) do { \ if (IS_IN_ARRAY(flags)) { \ (*env)->Get##JTYPE##ArrayRegion(env, obj, offset, length, (NTYPE *) array->elems); \ if (unlikely((*env)->ExceptionCheck(env) != JNI_FALSE)) return NULL; \ } else if (unlikely((flags & ARRAY_CLEAR) != 0)) { \ memset(array->elems, 0, length * sizeof(NTYPE)); \ } \ } while (0) #define SET_COPYOUT(JTYPE, array, flags) \ (array)->copyout = IS_OUT_ARRAY(flags) \ ? (void (JNICALL *)(JNIEnv*, jobject, jsize, jsize, const void *))(*env)->Set##JTYPE##ArrayRegion \ : NULL #define SET_COPYIN(JTYPE, array, flags) \ (array)->copyin = IS_IN_ARRAY(flags) \ ? (void (JNICALL *)(JNIEnv*, jobject, jsize, jsize, void *))(*env)->Get##JTYPE##ArrayRegion \ : NULL #define GET_ARRAY_BUFFER(JTYPE, NTYPE, flags, obj, offset, length, array) do { \ COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array); \ SET_COPYOUT(JTYPE, array, flags); \ } while (0) #define GET_ARRAY_HEAP(JTYPE, NTYPE, flags, obj, offset, length, array) do { \ int allocSize = sizeof(NTYPE) * (length + 1); \ (array)->elems = malloc(allocSize); \ if (unlikely((array)->elems == NULL)) { \ throwException(env, OutOfMemory, "failed to allocate native array of %d bytes", allocSize); \ return NULL; \ } \ COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array); \ SET_COPYOUT(JTYPE, array, flags); \ } while(0) void* jffi_getArrayHeap(JNIEnv* env, jobject buf, jsize offset, jsize length, int type, Array* array) { array->array = buf; array->offset = offset; array->length = length; array->type = type; array->copyin = NULL; array->copyout = NULL; array->release = releaseHeapArray; /* * Byte arrays are used for struct backing in both jaffl and jruby ffi, so * are the most likely path. */ if (likely((type & ARGPRIM_MASK) == com_kenai_jffi_ObjectBuffer_BYTE)) { GET_ARRAY_HEAP(Byte, jbyte, type, buf, offset, length, array); // If the array was really a string, nul terminate it if ((type & (ARRAY_NULTERMINATE | ARRAY_IN | ARRAY_OUT)) != ARRAY_OUT) { *(((char *) array->elems) + length) = '\0'; } } else { switch (type & ARGPRIM_MASK) { case com_kenai_jffi_ObjectBuffer_SHORT: GET_ARRAY_HEAP(Short, jshort, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_INT: GET_ARRAY_HEAP(Int, jint, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_LONG: GET_ARRAY_HEAP(Long, jlong, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_FLOAT: GET_ARRAY_HEAP(Float, jfloat, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_DOUBLE: GET_ARRAY_HEAP(Double, jdouble, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_BOOLEAN: GET_ARRAY_HEAP(Boolean, jboolean, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_CHAR: GET_ARRAY_HEAP(Char, jchar, type, buf, offset, length, array); break; default: throwException(env, IllegalArgument, "invalid array type: %#x\n", type); return NULL; } } return array->elems; } void* jffi_getArrayBuffer(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array, void* buffer) { array->array = buf; array->elems = buffer; array->offset = offset; array->length = length; array->type = type; array->release = NULL; array->copyin = NULL; array->copyout = NULL; switch (type & ARGPRIM_MASK) { case com_kenai_jffi_ObjectBuffer_BYTE: GET_ARRAY_BUFFER(Byte, jbyte, type, buf, offset, length, array); // If the array was really a string, nul terminate it if ((type & (ARRAY_NULTERMINATE | ARRAY_IN | ARRAY_OUT)) != ARRAY_OUT) { *(((char *) array->elems) + length) = '\0'; } break; case com_kenai_jffi_ObjectBuffer_SHORT: GET_ARRAY_BUFFER(Short, jshort, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_INT: GET_ARRAY_BUFFER(Int, jint, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_LONG: GET_ARRAY_BUFFER(Long, jlong, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_FLOAT: GET_ARRAY_BUFFER(Float, jfloat, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_DOUBLE: GET_ARRAY_BUFFER(Double, jdouble, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_BOOLEAN: GET_ARRAY_BUFFER(Boolean, jboolean, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_CHAR: GET_ARRAY_BUFFER(Char, jchar, type, buf, offset, length, array); break; default: throwException(env, IllegalArgument, "Invalid array type: %#x\n", type); return NULL; } return array->elems; } int jffi_arraySize(int length, int type) { switch (type & ARGPRIM_MASK) { case com_kenai_jffi_ObjectBuffer_BYTE: return length * sizeof(jbyte); case com_kenai_jffi_ObjectBuffer_SHORT: return length * sizeof(jshort); case com_kenai_jffi_ObjectBuffer_INT: return length * sizeof(jint); case com_kenai_jffi_ObjectBuffer_LONG: return length * sizeof(jlong); case com_kenai_jffi_ObjectBuffer_FLOAT: return length * sizeof(jfloat); case com_kenai_jffi_ObjectBuffer_DOUBLE: return length * sizeof(jdouble); case com_kenai_jffi_ObjectBuffer_BOOLEAN: return length * sizeof(jboolean); case com_kenai_jffi_ObjectBuffer_CHAR: return length * sizeof(jchar); default: return length * 8; } } static void jffi_releaseCriticalArray(JNIEnv* env, Array *array) { (*env)->ReleasePrimitiveArrayCritical(env, array->array, array->elems, 0); } void* jffi_getArrayCritical(JNIEnv* env, jobject buf, jsize offset, jsize length, int type, struct Array* array) { array->array = buf; array->offset = offset; array->length = length; array->type = type; array->copyin = NULL; array->copyout = NULL; array->elems = (*env)->GetPrimitiveArrayCritical(env, array->array, NULL); if (unlikely(array->elems == NULL)) { if (!(*env)->ExceptionCheck(env)) { throwException(env, NullPointer, "failed to pin native array"); } return NULL; } array->release = jffi_releaseCriticalArray; return (char *) array->elems + offset; } void jffi_releaseArrays(JNIEnv *env, Array* arrays, int arrayCount) { int aryIdx; for (aryIdx = arrayCount - 1; aryIdx >= 0; aryIdx--) { Array* array = &arrays[aryIdx]; if (IS_OUT_ARRAY(array->type) && array->copyout != NULL) { if ((*env)->ExceptionCheck(env) == JNI_FALSE) { (*array->copyout)(env, array->array, array->offset, array->length, array->elems); } } if (unlikely(array->release != NULL)) { (*array->release)(env, array); } } } jffi-1.2.7/jni/jffi/Array.h000066400000000000000000000072241247047424400154010ustar00rootroot00000000000000/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef jffi_Array_h #define jffi_Array_h // // WARNING! Do not change the layout of this struct, it may be used from assembler // typedef struct Array { void (JNICALL *copyin)(JNIEnv* env, jobject array, jsize start, jsize len, void *buf); void (JNICALL *copyout)(JNIEnv* env, jobject array, jsize start, jsize len, const void *buf); void (*release)(JNIEnv *env, struct Array *); jobject array; void* elems; int offset; int length; int type; int bytesize; // total size of array in bytes } Array; extern bool jffi_getInitArray(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array); extern void* jffi_getArrayBuffer(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array, void* buffer); extern void* jffi_getArrayHeap(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array); extern void* jffi_getArrayCritical(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array); extern int jffi_arraySize(int length, int type); extern void jffi_releaseArrays(JNIEnv* env, Array* arrays, int arrayCount); #include "com_kenai_jffi_ObjectBuffer.h" #define OBJ_INDEX_MASK com_kenai_jffi_ObjectBuffer_INDEX_MASK #define OBJ_INDEX_SHIFT com_kenai_jffi_ObjectBuffer_INDEX_SHIFT #define ARRAY_NULTERMINATE com_kenai_jffi_ObjectBuffer_ZERO_TERMINATE #define ARRAY_IN com_kenai_jffi_ObjectBuffer_IN #define ARRAY_OUT com_kenai_jffi_ObjectBuffer_OUT #define ARRAY_PINNED com_kenai_jffi_ObjectBuffer_PINNED #define ARRAY_CLEAR com_kenai_jffi_ObjectBuffer_CLEAR #define IS_PINNED_ARRAY(flags) \ (((flags) & (com_kenai_jffi_ObjectBuffer_ARRAY | com_kenai_jffi_ObjectBuffer_PINNED)) == (com_kenai_jffi_ObjectBuffer_ARRAY | com_kenai_jffi_ObjectBuffer_PINNED)) #define IS_UNPINNED_ARRAY(flags) \ (((flags) & (com_kenai_jffi_ObjectBuffer_ARRAY | com_kenai_jffi_ObjectBuffer_PINNED)) == com_kenai_jffi_ObjectBuffer_ARRAY) #define IS_OUT_ARRAY(flags) (((flags) & (com_kenai_jffi_ObjectBuffer_ARRAY | ARRAY_IN | ARRAY_OUT)) != (com_kenai_jffi_ObjectBuffer_ARRAY | ARRAY_IN)) #define IS_IN_ARRAY(flags) (((flags) & (com_kenai_jffi_ObjectBuffer_ARRAY | ARRAY_IN | ARRAY_OUT)) != (com_kenai_jffi_ObjectBuffer_ARRAY | ARRAY_OUT)) #define RELEASE_ARRAYS(env, arrays, arrayCount) do { if (unlikely(arrayCount > 0)) jffi_releaseArrays(env, arrays, arrayCount); } while (0) #endif /* jffi_Array_h */ jffi-1.2.7/jni/jffi/CallContext.c000066400000000000000000000171141247047424400165350ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include #if defined(__sun) || defined(_AIX) # include # include #endif #ifdef _WIN32 # include #endif #include #include #include "jffi.h" #include "Exception.h" #include "CallContext.h" #include "com_kenai_jffi_Foreign.h" #ifndef MAX # define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif static inline int FFI_ALIGN(int v, int a) { return ((((size_t) v) - 1) | (a - 1)) +1; } /* * Class: com_kenai_jffi_Foreign * Method: newCallContext * Signature: (I[II)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newCallContext(JNIEnv* env, jobject self, jlong returnType, jlongArray paramArray, jint flags) { CallContext* ctx = NULL; jlong* paramTypes; int paramCount, i, rawOffset = 0; bool isFastInt = false, isFastLong = false; ffi_type* ffiParamTypes; int ffiStatus; int abi; paramCount = (*env)->GetArrayLength(env, paramArray); ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext"); goto cleanup; } ctx->ffiParamTypes = calloc(MAX(1, paramCount), sizeof(ffi_type *)); if (ctx->ffiParamTypes == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext#ffiParamTypes"); goto cleanup; } ctx->rawParamOffsets = calloc(MAX(1, paramCount), sizeof(*ctx->rawParamOffsets)); if (ctx->rawParamOffsets == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext#rawParamOffsets"); goto cleanup; } paramTypes = alloca(paramCount * sizeof(jlong)); (*env)->GetLongArrayRegion(env, paramArray, 0, paramCount, paramTypes); ctx->resultMask = (((ffi_type *) j2p(returnType))->size > 4) ? ~0UL : 0xffffffffUL; #if defined(__i386__) || defined(__x86_64__) isFastInt = true; isFastLong = true; switch (((ffi_type *) j2p(returnType))->type) { case FFI_TYPE_INT: case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: #if defined(__i386__) case FFI_TYPE_POINTER: #endif #if !defined(__x86_64__) isFastLong = false; #endif break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: #if defined(__x86_64__) case FFI_TYPE_POINTER: #endif isFastInt = false; break; case FFI_TYPE_VOID: break; default: isFastInt = false; isFastLong = false; break; } #endif for (i = 0; i < paramCount; ++i) { ffi_type* type = (ffi_type *) j2p(paramTypes[i]); if (type == NULL) { throwException(env, IllegalArgument, "Invalid parameter type: %#x", paramTypes[i]); goto cleanup; } ctx->ffiParamTypes[i] = type; ctx->rawParamOffsets[i] = rawOffset; rawOffset += FFI_ALIGN(type->size, FFI_SIZEOF_ARG); #if defined(__i386__) || defined(__x86_64__) switch (type->type) { case FFI_TYPE_INT: case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: #if defined(__i386__) case FFI_TYPE_POINTER: #endif #if !defined(__x86_64__) isFastLong = false; #endif break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: #if defined(__x86_64__) case FFI_TYPE_POINTER: #endif isFastInt = false; break; default: isFastInt = false; isFastLong = false; break; } #endif } // On win32, we might need to set the abi to stdcall - but win64 only supports cdecl/default #if defined(_WIN32) && !defined(_WIN64) abi = (flags & com_kenai_jffi_Foreign_F_STDCALL) != 0 ? FFI_STDCALL : FFI_DEFAULT_ABI; #else abi = FFI_DEFAULT_ABI; #endif // Cannot bypass FFI unless ABI is cdecl if (abi != FFI_DEFAULT_ABI) { isFastInt = false; isFastLong = false; } ffiStatus = ffi_prep_cif(&ctx->cif, abi, paramCount, (ffi_type *) j2p(returnType), ctx->ffiParamTypes); switch (ffiStatus) { case FFI_OK: break; case FFI_BAD_TYPEDEF: throwException(env, IllegalArgument, "Bad typedef"); goto cleanup; case FFI_BAD_ABI: throwException(env, Runtime, "Invalid ABI"); goto cleanup; default: throwException(env, Runtime, "Unknown FFI error"); } ctx->rawParameterSize = rawOffset; ctx->flags |= (flags & com_kenai_jffi_Foreign_F_NOERRNO) == 0 ? CALL_CTX_SAVE_ERRNO : 0; ctx->flags |= isFastInt ? CALL_CTX_FAST_INT : 0; ctx->flags |= isFastLong ? CALL_CTX_FAST_LONG : 0; ctx->flags |= (flags & com_kenai_jffi_Foreign_F_PROTECT) != 0 ? CALL_CTX_FAULT_PROT : 0; return p2j(ctx); cleanup: if (ctx != NULL) { if (ctx->rawParamOffsets != NULL) { free(ctx->rawParamOffsets); } if (ctx->ffiParamTypes != NULL) { free(ctx->ffiParamTypes); } free(ctx); } return 0LL; } /* * Class: com_kenai_jffi_Foreign * Method: freeCallContext * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeCallContext(JNIEnv* env, jobject self, jlong handle) { CallContext* ctx = (CallContext *) j2p(handle); if (ctx != NULL) { if (ctx->rawParamOffsets != NULL) { free(ctx->rawParamOffsets); } if (ctx->ffiParamTypes != NULL) { free(ctx->ffiParamTypes); } free(ctx); } } /* * Class: com_kenai_jffi_Foreign * Method: getCallContextRawParameterSize * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getCallContextRawParameterSize(JNIEnv* env, jobject self, jlong handle) { CallContext* ctx = (CallContext *) j2p(handle); return ctx->rawParameterSize; } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_setCallContextErrorFunction(JNIEnv* env, jobject self, jlong handle, jlong fn) { CallContext* ctx = (CallContext *) j2p(handle); ctx->error_fn = j2p(fn); } jffi-1.2.7/jni/jffi/CallContext.h000066400000000000000000000037531247047424400165460ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef JFFI_CALLCONTEXT_H #define JFFI_CALLCONTEXT_H #include typedef struct CallContext { /** IMPORTANT: keep ffi_cif as the first field */ ffi_cif cif; int rawParameterSize; ffi_type** ffiParamTypes; int* rawParamOffsets; bool saveErrno; int flags; long resultMask; int (*error_fn)(void); } CallContext; extern void jffi_save_errno_ctx(CallContext* ctx); #define CALL_CTX_SAVE_ERRNO (0x1) #define CALL_CTX_FAST_INT (0x2) #define CALL_CTX_FAST_LONG (0x4) #define CALL_CTX_FAULT_PROT (0x8) #define SAVE_ERRNO(ctx) do { \ if (unlikely((ctx->flags & CALL_CTX_SAVE_ERRNO) != 0)) { \ jffi_save_errno_ctx(ctx); \ } \ } while(0) #endif /* JFFI_CALLCONTEXT_H */ jffi-1.2.7/jni/jffi/ClosureMagazine.c000066400000000000000000000324131247047424400174040ustar00rootroot00000000000000/* * Copyright (C) 2007-2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include #include #include #if defined(__sun) || defined(_AIX) # include # include #endif #ifdef _WIN32 # include #endif #include #include "jffi.h" #include "Exception.h" #include "Type.h" #include "CallContext.h" #include "MemoryUtil.h" #include "FaultProtect.h" #include "com_kenai_jffi_Foreign.h" #define THREAD_ATTACH_THRESHOLD (1000) struct Closure; typedef struct ClosureMagazine { CallContext* callContext; jmethodID methodID; JavaVM* jvm; void* code; struct Closure* closures; int nclosures; int nextclosure; int callWithPrimitiveParameters; } Magazine; typedef struct Closure { void* code; /* the code address must be the first member of this struct; used by java */ jobject javaObject; Magazine* magazine; } Closure; static bool closure_prep(ffi_cif* cif, void* code, Closure* closure, char* errbuf, size_t errbufsize); JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newClosureMagazine(JNIEnv *env, jobject self, jlong ctxAddress, jobject closureMethod, jboolean callWithPrimitiveParameters) { CallContext* ctx = (CallContext *) j2p(ctxAddress); Closure* list = NULL; Magazine* magazine = NULL; caddr_t code = NULL; char errmsg[256]; int i; int trampolineSize, pageSize, nclosures; trampolineSize = roundup(sizeof(ffi_closure), 8); pageSize = jffi_getPageSize(); nclosures = pageSize / trampolineSize; magazine = calloc(1, sizeof(*magazine)); list = calloc(nclosures, sizeof(*list)); code = jffi_allocatePages(1); if (magazine == NULL || list == NULL || code == NULL) { snprintf(errmsg, sizeof(errmsg), "failed to allocate a page. errno=%d (%s)", errno, strerror(errno)); goto error; } // Thread all the closure handles onto a list, and init each one for (i = 0; i < nclosures; ++i) { Closure* closure = &list[i]; closure->magazine = magazine; closure->code = (code + (i * trampolineSize)); if (!closure_prep(&ctx->cif, closure->code, closure, errmsg, sizeof(errmsg))) { goto error; } } if (!jffi_makePagesExecutable(code, 1)) { snprintf(errmsg, sizeof(errmsg), "failed to make page executable. errno=%d (%s)", errno, strerror(errno)); goto error; } magazine->methodID = (*env)->FromReflectedMethod(env, closureMethod); if (magazine->methodID == NULL) { throwException(env, IllegalArgument, "could not obtain reference to closure method"); goto error; } /* Track the allocated page + Closure memory area */ magazine->closures = list; magazine->nextclosure = 0; magazine->nclosures = nclosures; magazine->code = code; magazine->callWithPrimitiveParameters = callWithPrimitiveParameters; (*env)->GetJavaVM(env, &magazine->jvm); return p2j(magazine); error: free(list); free(magazine); if (code != NULL) { jffi_freePages(code, 1); } throwException(env, Runtime, errmsg); return 0L; } /* * Class: com_kenai_jffi_Foreign * Method: freeClosureMagazine * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeClosureMagazine(JNIEnv *env, jobject self, jlong magAddress) { Magazine* magazine = (Magazine *) j2p(magAddress); Closure* closure; int i; for (i = 0; i < magazine->nextclosure; ++i) { (*env)->DeleteGlobalRef(env, magazine->closures[i].javaObject); } free(magazine->closures); jffi_freePages(magazine->code, 1); free(magazine); } /* * Class: com_kenai_jffi_Foreign * Method: closureMagazineGet * Signature: (JLjava/lang/Object;)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_closureMagazineGet(JNIEnv *env, jobject self, jlong magAddress, jobject closureProxy) { Magazine* magazine = (Magazine *) j2p(magAddress); if (magazine->nextclosure < magazine->nclosures) { Closure* closure = &magazine->closures[magazine->nextclosure]; closure->javaObject = (*env)->NewGlobalRef(env, closureProxy); if (closure->javaObject == NULL) { throwException(env, IllegalArgument, "could not obtain reference to java object"); return 0L; } magazine->nextclosure++; return p2j(closure); } return 0L; } static void closure_begin(Closure* closure, JNIEnv** penv, bool* detach) { JavaVM* jvm = closure->magazine->jvm; *detach = (*jvm)->GetEnv(jvm, (void **)penv, JNI_VERSION_1_4) != JNI_OK && (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void **)penv, NULL) == JNI_OK; #ifndef _WIN32 if (*detach && thread_data_get()->attach_count++ >= THREAD_ATTACH_THRESHOLD) { thread_data_get()->attached_vm = jvm; *detach = false; } #endif if ((**penv)->ExceptionCheck(*penv)) { (**penv)->ExceptionClear(*penv); } } static void closure_end(Closure* closure, JNIEnv* env, bool detach) { JavaVM* jvm = closure->magazine->jvm; bool clearException = detach; #ifndef _WIN32 if (thread_data_get()->attached_vm != NULL) { clearException = true; } #endif if (env != NULL && clearException) { if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); } } if (detach) { (*jvm)->DetachCurrentThread(jvm); } } static void closure_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data) { Closure* closure = (Closure *) user_data; JNIEnv* env; int i; bool detach; #if FAULT_PROTECT_ENABLED ThreadData* td = thread_data_get(); FaultData* fdp; #endif closure_begin(closure, &env, &detach); #if FAULT_PROTECT_ENABLED fdp = td->fault_data; td->fault_data = NULL; #endif if (closure->magazine->callWithPrimitiveParameters) { // allocate one more than the parameter count (for the struct return value) jvalue* jparams = alloca((cif->nargs + 1) * sizeof(jvalue)); for (i = 0; i < (int) cif->nargs; i++) { jvalue* vp = &jparams[i]; vp->j = 0LL; // zero out any bits not filled below switch (cif->arg_types[i]->type) { case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: vp->b = *(jbyte *) parameters[i]; break; case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: vp->s = *(jshort *) parameters[i]; break; case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: case FFI_TYPE_INT: vp->i = *(jint *) parameters[i]; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: vp->j = *(jlong *) parameters[i]; break; case FFI_TYPE_FLOAT: vp->i = *(jfloat *) parameters[i]; break; case FFI_TYPE_DOUBLE: vp->i = *(jdouble *) parameters[i]; break; case FFI_TYPE_POINTER: if (cif->arg_types[i]->size == 4) { vp->i = (uintptr_t) *(void **) parameters[i]; } else { vp->j = p2j(*(void **) parameters[i]); } break; case FFI_TYPE_STRUCT: #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: #endif vp->j = p2j(parameters[i]); break; default: memset(vp, 0, sizeof(*vp)); break; } } switch (cif->rtype->type) { case FFI_TYPE_VOID: (*env)->CallVoidMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); *((ffi_sarg *) retval) = 0; break; case FFI_TYPE_SINT8: *((ffi_sarg *) retval) = (*env)->CallByteMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_SINT16: *((ffi_sarg *) retval) = (*env)->CallShortMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_SINT32: case FFI_TYPE_INT: *((ffi_sarg *) retval) = (*env)->CallIntMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_UINT8: *((ffi_arg *) retval) = (*env)->CallByteMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_UINT16: *((ffi_arg *) retval) = (*env)->CallShortMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_UINT32: *((ffi_arg *) retval) = (*env)->CallIntMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_SINT64: *((int64_t *) retval) = (*env)->CallLongMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_UINT64: *((uint64_t *) retval) = (*env)->CallLongMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_POINTER: if (cif->rtype->size == 4) { *((ffi_arg *) retval) = (*env)->CallIntMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); } else { *((ffi_arg *) retval) = (*env)->CallLongMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); } break; case FFI_TYPE_FLOAT: *((float *) retval) = (*env)->CallFloatMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_DOUBLE: *((double *) retval) = (*env)->CallDoubleMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; case FFI_TYPE_STRUCT: #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: #endif // stuff the retval in as the last parameter passed to the java method jparams[cif->nargs].j = p2j(retval); (*env)->CallVoidMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); break; default: memset(retval, 0, cif->rtype->size); } } else { jvalue jparams[2]; jparams[0].j = p2j(retval); jparams[1].j = p2j(parameters); // // Do the actual invoke - the java code will unmarshal the arguments // (*env)->CallVoidMethodA(env, closure->javaObject, closure->magazine->methodID, jparams); } if ((*env)->ExceptionCheck(env)) { memset(retval, 0, cif->rtype->size); } #if FAULT_PROTECT_ENABLED td->fault_data = fdp; #endif closure_end(closure, env, detach); } static bool closure_prep(ffi_cif* cif, void* code, Closure* closure, char* errbuf, size_t errbufsize) { ffi_status status; status = ffi_prep_closure(code, cif, closure_invoke, closure); switch (status) { case FFI_OK: return true; case FFI_BAD_ABI: snprintf(errbuf, errbufsize, "Invalid ABI specified"); //throwException(env, IllegalArgument, "Invalid ABI specified"); return false; case FFI_BAD_TYPEDEF: snprintf(errbuf, errbufsize, "Invalid argument type specified"); //throwException(env, IllegalArgument, "Invalid argument type specified"); return false; default: snprintf(errbuf, errbufsize, "Unknown FFI error"); //throwException(env, IllegalArgument, "Unknown FFI error"); return false; } } jffi-1.2.7/jni/jffi/Exception.c000066400000000000000000000043521247047424400162530ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include "Exception.h" void jffi_throwExceptionByName(JNIEnv* env, const char* exceptionName, const char* fmt, ...) { va_list ap; char buf[1024] = { 0 }; va_start(ap, fmt); vsnprintf(buf, sizeof(buf) - 1, fmt, ap); (*env)->PushLocalFrame(env, 10); jclass exceptionClass = (*env)->FindClass(env, exceptionName); if (exceptionClass != NULL) { (*env)->ThrowNew(env, exceptionClass, buf); } (*env)->PopLocalFrame(env, NULL); va_end(ap); } const char* jffi_IllegalArgumentException = "java/lang/IllegalArgumentException"; const char* jffi_NullPointerException = "java/lang/NullPointerException"; const char* jffi_OutOfBoundsException = "java/lang/IndexOutOfBoundsException"; const char* jffi_OutOfMemoryException = "java/lang/OutOfMemoryError"; const char* jffi_RuntimeException = "java/lang/RuntimeError"; const char* jffi_UnsatisfiedLinkException = "java/lang/UnsatisfiedLinkError"; jffi-1.2.7/jni/jffi/Exception.h000066400000000000000000000036271247047424400162640ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef jffi_Exception_h #define jffi_Exception_h #ifdef __cplusplus extern "C" { #endif #define throwException(env, name, fmt, a...) \ jffi_throwExceptionByName((env), jffi_##name##Exception, fmt, ##a) extern const char* jffi_IllegalArgumentException; extern const char* jffi_NullPointerException; extern const char* jffi_OutOfBoundsException; extern const char* jffi_OutOfMemoryException; extern const char* jffi_RuntimeException; extern const char* jffi_UnsatisfiedLinkException; extern void jffi_throwExceptionByName(JNIEnv* env, const char* exceptionName, const char* fmt, ...); #ifdef __cplusplus } #endif #endif /* jffi_Exception_h */ jffi-1.2.7/jni/jffi/FastIntInvoke.c000066400000000000000000000150361247047424400170420ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include #include #include "endian.h" #include "jffi.h" #include "Exception.h" #include "CallContext.h" #include "LastError.h" #include "FaultProtect.h" #include "com_kenai_jffi_Foreign.h" #include "FastNumeric.h" #if !FAULT_PROTECT_ENABLED # define CALL(ctx, stmt) do { stmt; SAVE_ERRNO(ctx); } while(0) #else # define CALL(ctx, stmt) FAULTPROT_CTX(env, ctx, stmt, return 0) #endif /* * Class: com_kenai_jffi_Foreign * Method: invokeVrI * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI0(JNIEnv* env, jclass self, jlong ctxAddress, jlong function) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeI0(ctx, j2p(function), &retval)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI1(JNIEnv* env, jclass self, jlong ctxAddress, jlong function, jint arg1) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeI1(ctx, j2p(function), &retval, arg1)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI2(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeI2(ctx, j2p(function), &retval, arg1, arg2)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI3(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2, jint arg3) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeI3(ctx, j2p(function), &retval, arg1, arg2, arg3)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI4(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2, jint arg3, jint arg4) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeI4(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI5(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2, jint arg3, jint arg4, jint arg5) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeI5(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4, arg5)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI6(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2, jint arg3, jint arg4, jint arg5, jint arg6) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeI6(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4, arg5, arg6)); return (jint) retval; } /* * Class: com_kenai_jffi_Foreign * Method: invokeVrI * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI0NoErrno(JNIEnv* env, jclass self, jlong ctxAddress, jlong function) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; invokeI0(ctx, j2p(function), &retval); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI1NoErrno(JNIEnv* env, jclass self, jlong ctxAddress, jlong function, jint arg1) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; invokeI1(ctx, j2p(function), &retval, arg1); return (int) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI2NoErrno(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; invokeI2(ctx, j2p(function), &retval, arg1, arg2); return (int) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI3NoErrno(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2, jint arg3) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; invokeI3(ctx, j2p(function), &retval, arg1, arg2, arg3); return (int) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI4NoErrno(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2, jint arg3, jint arg4) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; invokeI4(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI5NoErrno(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2, jint arg3, jint arg4, jint arg5) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; invokeI5(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4, arg5); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeI6NoErrno(JNIEnv*env, jobject self, jlong ctxAddress, jlong function, jint arg1, jint arg2, jint arg3, jint arg4, jint arg5, jint arg6) { CallContext *ctx = (CallContext *) j2p(ctxAddress); ffi_sarg retval; invokeI6(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4, arg5, arg6); return (jint) retval; } jffi-1.2.7/jni/jffi/FastLongInvoke.c000066400000000000000000000163501247047424400172070ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #ifdef __sun # include #endif #include #include #include #include "endian.h" #include "jffi.h" #include "Exception.h" #include "CallContext.h" #include "LastError.h" #include "FaultProtect.h" #include "com_kenai_jffi_Foreign.h" #include "FastNumeric.h" /* for return values <= sizeof(long), need to use an ffi_sarg sized return value */ #if BYTE_ORDER == BIG_ENDIAN # define RETVAL(retval, ctx) ((ctx->cif.rtype)->size > sizeof(ffi_sarg) ? (retval).j : (retval).sarg) #else # define RETVAL(retval, ctx) ((retval).j) #endif /* * Class: com_kenai_jffi_Foreign * Method: invokeVrL * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL0(JNIEnv* env, jobject self, jlong ctxAddress, jlong function) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL0(ctx, j2p(function), &retval), return 0); return RETVAL(retval, ctx); } /* * Class: com_kenai_jffi_Foreign * Method: invokeVrL * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL0NoErrno(JNIEnv* env, jobject self, jlong ctxAddress, jlong function) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL0(ctx, j2p(function), &retval), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL1(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL1(ctx, j2p(function), &retval, arg1), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL1NoErrno(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL1(ctx, j2p(function), &retval, arg1), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL2(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL2(ctx, j2p(function), &retval, arg1, arg2), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL2NoErrno(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL2(ctx, j2p(function), &retval, arg1, arg2), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL3(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL3(ctx, j2p(function), &retval, arg1, arg2, arg3), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL3NoErrno(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL3(ctx, j2p(function), &retval, arg1, arg2, arg3), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL4(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL4(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL4NoErrno(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL4(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL5(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL5(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4, arg5), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL5NoErrno(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL5(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4, arg5), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL6(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5, jlong arg6) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL6(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4, arg5, arg6), return 0); return RETVAL(retval, ctx); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeL6NoErrno(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5, jlong arg6) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, invokeL6(ctx, j2p(function), &retval, arg1, arg2, arg3, arg4, arg5, arg6), return 0); return RETVAL(retval, ctx); } jffi-1.2.7/jni/jffi/FastNumeric.h000066400000000000000000000066101247047424400165410ustar00rootroot00000000000000#ifndef JFFI_FASTNUMERIC_H #define JFFI_FASTNUMERIC_H #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) # define INT_BYPASS_FFI #endif #if defined(__x86_64__) && defined(__GNUC__) # define LONG_BYPASS_FFI #endif # if defined(__x86_64) || defined(__amd64) # define CLEAR_VARARGS ({__asm__ __volatile__("xorq %%rax, %%rax" ::: "rax");}) # else # define CLEAR_VARARGS do { } while(0) # endif #if defined(INT_BYPASS_FFI) # define invokeI0(ctx, fn, retval) do { \ CLEAR_VARARGS; *(retval) = ((jint (*)()) (fn))(); \ } while (0) # define invokeI1(ctx, fn, retval, arg1) do { \ CLEAR_VARARGS; *(retval) = ((jint (*)(jint)) (fn))(arg1); \ } while (0) # define invokeI2(ctx, fn, retval, arg1, arg2) do { \ CLEAR_VARARGS; *(retval) = ((jint (*)(jint, jint)) (fn))((arg1), (arg2)); \ } while (0) # define invokeI3(ctx, fn, retval, arg1, arg2, arg3) do { \ CLEAR_VARARGS; *(retval) = ((jint (*)(jint, jint, jint)) (fn))(arg1, arg2, arg3); \ } while (0) # define invokeI4(ctx, fn, retval, arg1, arg2, arg3, arg4) do { \ CLEAR_VARARGS; *(retval) = ((jint (*)(jint, jint, jint, jint)) (fn))(arg1, arg2, arg3, arg4); \ } while (0) # define invokeI5(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5) do { \ CLEAR_VARARGS; *(retval) = ((jint (*)(jint, jint, jint, jint, jint)) (fn))(arg1, arg2, arg3, arg4, arg5); \ } while (0) # define invokeI6(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5, arg6) do { \ CLEAR_VARARGS; *(retval) = ((jint (*)(jint, jint, jint, jint, jint, jint)) (fn))(arg1, arg2, arg3, arg4, arg5, arg6); \ } while (0) #else /* non-i386, non-x86_64 */ # define invokeI0 ffi_call0 # define invokeI1 ffi_call1 # define invokeI2 ffi_call2 # define invokeI3 ffi_call3 # define invokeI4 ffi_call4 # define invokeI5 ffi_call5 # define invokeI6 ffi_call6 #endif #if defined(LONG_BYPASS_FFI) # define invokeL0(ctx, fn, retval) do { \ CLEAR_VARARGS; (retval)->j = ((jlong (*)()) (fn))(); \ } while (0) # define invokeL1(ctx, fn, retval, arg1) do { \ CLEAR_VARARGS; (retval)->j = ((jlong (*)(jlong)) (fn))(arg1); \ } while (0) # define invokeL2(ctx, fn, retval, arg1, arg2) do { \ CLEAR_VARARGS; (retval)->j = ((jlong (*)(jlong, jlong)) (fn))((arg1), (arg2)); \ } while (0) # define invokeL3(ctx, fn, retval, arg1, arg2, arg3) do { \ CLEAR_VARARGS; (retval)->j = ((jlong (*)(jlong, jlong, jlong)) (fn))(arg1, arg2, arg3); \ } while (0) # define invokeL4(ctx, fn, retval, arg1, arg2, arg3, arg4) do { \ CLEAR_VARARGS; (retval)->j = ((jlong (*)(jlong, jlong, jlong, jlong)) (fn))(arg1, arg2, arg3, arg4); \ } while (0) # define invokeL5(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5) do { \ CLEAR_VARARGS; (retval)->j = ((jlong (*)(jlong, jlong, jlong, jlong, jlong)) (fn))(arg1, arg2, arg3, arg4, arg5); \ } while (0) # define invokeL6(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5, arg6) do { \ CLEAR_VARARGS; (retval)->j = ((jlong (*)(jlong, jlong, jlong, jlong, jlong, jlong)) (fn))(arg1, arg2, arg3, arg4, arg5, arg6); \ } while (0) #else /* non-i386, non-x86_64 */ # define invokeL0 ffi_call0 # define invokeL1 ffi_call1 # define invokeL2 ffi_call2 # define invokeL3 ffi_call3 # define invokeL4 ffi_call4 # define invokeL5 ffi_call5 # define invokeL6 ffi_call6 #endif #endif /* JFFI_FASTNUMERIC_H */jffi-1.2.7/jni/jffi/FastNumericInvoker.c000066400000000000000000000363611247047424400201000ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #ifdef __sun # include #endif #include #include #include #include "endian.h" #include "jffi.h" #include "Exception.h" #include "CallContext.h" #include "Array.h" #include "LastError.h" #include "FaultProtect.h" #include "com_kenai_jffi_Foreign.h" #include "FastNumeric.h" /* for return values <= sizeof(long), need to use an ffi_sarg sized return value */ #if BYTE_ORDER == BIG_ENDIAN # define RETVAL(retval, ctx) ((ctx->cif.rtype)->size > sizeof(ffi_sarg) ? (retval).j : (retval).sarg) #else # define RETVAL(retval, ctx) ((retval).j) #endif #define MAX_STACK_ARRAY (1024) #define OBJIDX(flags) ((flags & com_kenai_jffi_ObjectBuffer_INDEX_MASK) >> com_kenai_jffi_ObjectBuffer_INDEX_SHIFT) #define OBJTYPE(flags) ((flags) & com_kenai_jffi_ObjectBuffer_TYPE_MASK) #define IS_ARRAY(flags) \ ((OBJTYPE(flags) & ~com_kenai_jffi_ObjectBuffer_PRIM_MASK) == com_kenai_jffi_ObjectBuffer_ARRAY) #define IS_BUFFER(flags) \ ((OBJTYPE(flags) & ~com_kenai_jffi_ObjectBuffer_PRIM_MASK) == com_kenai_jffi_ObjectBuffer_BUFFER) typedef struct Pinned { jobject object; int offset; int length; int flags; } Pinned; typedef struct ObjectParam { jobject object; int offset; int length; int flags; } ObjectParam; static jlong call1(JNIEnv* env, CallContext* ctx, void* function, jlong n1); static jlong call2(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2); static jlong call3(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2, jlong n3); static jlong call4(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2, jlong n3, jlong n4); static jlong call5(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2, jlong n3, jlong n4, jlong n5); static jlong call6(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2, jlong n3, jlong n4, jlong n5, jlong n6); static bool pin_arrays(JNIEnv* env, Pinned* pinned, int pinnedCount, Array* arrays, int *arrayCount, jlong* v); static bool object_to_ptr(JNIEnv* env, jobject obj, int off, int len, int f, jlong* vp, Array* arrays, int* arrayCount, Pinned* pinned, int* pinnedCount); /* * Class: com_kenai_jffi_Foreign * Method: invokeVrL * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeN0(JNIEnv* env, jobject self, jlong ctxAddress, jlong function) { CallContext* ctx = (CallContext *) j2p(ctxAddress); FFIValue retval; FAULTPROT_CTX(env, ctx, if (0) { #if defined(LONG_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_LONG) != 0)) { invokeL0(ctx, j2p(function), &retval); #endif #if defined(INT_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_INT) != 0)) { invokeI0(ctx, j2p(function), &retval.j); #endif } else { ffi_call0(ctx, j2p(function), &retval); }, return 0); return RETVAL(retval, ctx); } /* * Class: com_kenai_jffi_Foreign * Method: invokeLrL * Signature: (JJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeN1(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1) { return call1(env, (CallContext *) j2p(ctxAddress), j2p(function), arg1); } /* * Class: com_kenai_jffi_Foreign * Method: invokeLLrL * Signature: (JJJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeN2(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2) { return call2(env, (CallContext *) j2p(ctxAddress), j2p(function), arg1, arg2); } /* * Class: com_kenai_jffi_Foreign * Method: invokeLLLrL * Signature: (JJJJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeN3(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3) { return call3(env, (CallContext *) j2p(ctxAddress), j2p(function), arg1, arg2, arg3); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeN4(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4) { return call4(env, (CallContext *) j2p(ctxAddress), j2p(function), arg1, arg2, arg3, arg4); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeN5(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5) { return call5(env, (CallContext *) j2p(ctxAddress), j2p(function), arg1, arg2, arg3, arg4, arg5); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeN6(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5, jlong arg6) { return call6(env, (CallContext *) j2p(ctxAddress), j2p(function), arg1, arg2, arg3, arg4, arg5, arg6); } static jlong call1(JNIEnv* env, CallContext* ctx, void* function, jlong n1) { FFIValue retval; FAULTPROT_CTX(env, ctx, if (0) { #if defined(LONG_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_LONG) != 0)) { invokeL1(ctx, function, &retval, n1); #endif #if defined(INT_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_INT) != 0)) { invokeI1(ctx, function, &retval.j, (jint) n1); #endif } else { ffi_call1(ctx, function, &retval, n1); }, return 0); return RETVAL(retval, ctx); } static jlong call2(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2) { FFIValue retval; FAULTPROT_CTX(env, ctx, if (0) { #if defined(LONG_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_LONG) != 0)) { invokeL2(ctx, function, &retval, n1, n2); #endif #if defined(INT_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_INT) != 0)) { invokeI2(ctx, function, &retval.j, (jint) n1, (jint) n2); #endif } else { ffi_call2(ctx, function, &retval, n1, n2); }, return 0); return RETVAL(retval, ctx); } static jlong call3(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2, jlong n3) { FFIValue retval; FAULTPROT_CTX(env, ctx, if (0) { #if defined(LONG_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_LONG) != 0)) { invokeL3(ctx, function, &retval, n1, n2, n3); #endif #if defined(INT_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_INT) != 0)) { invokeI3(ctx, function, &retval.j, (jint) n1, (jint) n2, (jint) n3); #endif } else { ffi_call3(ctx, function, &retval, n1, n2, n3); }, return 0); return RETVAL(retval, ctx); } static jlong call4(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2, jlong n3, jlong n4) { FFIValue retval; FAULTPROT_CTX(env, ctx, if (0) { #if defined(LONG_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_LONG) != 0)) { invokeL4(ctx, function, &retval, n1, n2, n3, n4); #endif #if defined(INT_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_INT) != 0)) { invokeI4(ctx, function, &retval.j, (jint) n1, (jint) n2, (jint) n3, (jint) n4); #endif } else { ffi_call4(ctx, function, &retval, n1, n2, n3, n4); }, return 0); return RETVAL(retval, ctx); } static jlong call5(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2, jlong n3, jlong n4, jlong n5) { FFIValue retval; FAULTPROT_CTX(env, ctx, if (0) { #if defined(LONG_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_LONG) != 0)) { invokeL5(ctx, function, &retval, n1, n2, n3, n4, n5); #endif #if defined(INT_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_INT) != 0)) { invokeI5(ctx, function, &retval.j, (jint) n1, (jint) n2, (jint) n3, (jint) n4, (jint) n5); #endif } else { ffi_call5(ctx, function, &retval, n1, n2, n3, n4, n5); }, return 0); return RETVAL(retval, ctx); } static jlong call6(JNIEnv* env, CallContext* ctx, void* function, jlong n1, jlong n2, jlong n3, jlong n4, jlong n5, jlong n6) { FFIValue retval; FAULTPROT_CTX(env, ctx, if (0) { #if defined(LONG_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_LONG) != 0)) { invokeL6(ctx, function, &retval, n1, n2, n3, n4, n5, n6); #endif #if defined(INT_BYPASS_FFI) } else if (likely((ctx->flags & CALL_CTX_FAST_INT) != 0)) { invokeI6(ctx, function, &retval.j, (jint) n1, (jint) n2, (jint) n3, (jint) n4, (jint) n5, (jint) n6); #endif } else { ffi_call6(ctx, function, &retval, n1, n2, n3, n4, n5, n6); }, return 0); return RETVAL(retval, ctx); } static bool pin_arrays(JNIEnv* env, Pinned* pinned, int pinnedCount, Array* arrays, int *arrayCount, jlong* v) { int aryIdx; for (aryIdx = 0; aryIdx < pinnedCount; aryIdx++) { Pinned* p = &pinned[aryIdx]; Array* ary = &arrays[*arrayCount]; void* addr = jffi_getArrayCritical(env, p->object, p->offset, p->length, p->flags, ary); if (unlikely(addr == NULL)) { return false; } v[OBJIDX(p->flags)] = p2j(addr); (*arrayCount)++; } return true; } static bool object_to_ptr(JNIEnv* env, jobject obj, int off, int len, int f, jlong* vp, Array* arrays, int* arrayCount, Pinned* pinned, int* pinnedCount) { if (unlikely(obj == NULL)) { throwException(env, NullPointer, "null object for parameter %d", OBJIDX(f)); return false; } else if (unlikely(IS_PINNED_ARRAY(f))) { Pinned* p = &pinned[(*pinnedCount)++]; p->object = obj; p->offset = off; p->length = len; p->flags = f; *vp = 0LL; } else if (IS_ARRAY(f)) { *vp = p2j(jffi_getArrayHeap(env, obj, off, len, f, &arrays[*arrayCount])); if (unlikely(*vp == 0L)) { return false; } (*arrayCount)++; } else if (IS_BUFFER((f))) { caddr_t addr = (caddr_t) (*env)->GetDirectBufferAddress(env, obj); if (unlikely(addr == NULL)) { throwException(env, NullPointer, "could not get direct buffer address for parameter %d", OBJIDX(f)); return false; } *vp = p2j(addr + off); } else { throwException(env, IllegalArgument, "unsupported object type for parameter %d: %#x", OBJIDX(f), f); return false; } return true; } #define N1 n1 #define N2 N1, n2 #define N3 N2, n3 #define N4 N3, n4 #define N5 N4, n5 #define N6 N5, n6 #define INIT(n) \ const int MAX_PARAM_INDEX = (n) - 1; \ CallContext* ctx = (CallContext *) j2p(ctxAddress); \ Array arrays[(n)]; \ Pinned pinned[(n)]; \ int arrayCount = 0, pinnedCount = 0; \ jlong retval = 0; \ jlong v[] = { N##n } #define END \ error: \ RELEASE_ARRAYS(env, arrays, arrayCount); \ return retval #define ADDOBJ(obj, off, len, flags) do { \ int idx = OBJIDX(flags); \ if (unlikely(idx < 0 || idx > MAX_PARAM_INDEX)) { \ throwException(env, OutOfBounds, "invalid object parameter index %d (expected 0..%d)", \ idx, MAX_PARAM_INDEX); \ goto error; \ } \ if (likely(IS_UNPINNED_ARRAY(flags) && len < MAX_STACK_ARRAY)) { \ void* ptr = alloca(jffi_arraySize((len) + 1, (flags))); \ if (unlikely(jffi_getArrayBuffer(env, obj, off, len, flags, &arrays[arrayCount], ptr) == NULL)) { \ goto error; \ } \ v[idx] = p2j(ptr); \ arrayCount++; \ } else if (!object_to_ptr(env, obj, off, len, flags, &v[idx], arrays, &arrayCount, pinned, &pinnedCount)) { \ goto error; \ } \ } while (0) #define PIN_ARRAYS do { \ if (unlikely(pinnedCount > 0)) { \ if (!pin_arrays(env, pinned, pinnedCount, arrays, &arrayCount, v)) goto error; \ } \ } while(0) #define CALL(n, args...) \ PIN_ARRAYS; \ retval = call##n(env, ctx, j2p(function), args); \ END #define CALL1 CALL(1, v[0]) #define CALL2 CALL(2, v[0], v[1]) #define CALL3 CALL(3, v[0], v[1], v[2]) #define CALL4 CALL(4, v[0], v[1], v[2], v[3]) #define CALL5 CALL(5, v[0], v[1], v[2], v[3], v[4]) #define CALL6 CALL(6, v[0], v[1], v[2], v[3], v[4], v[5]) #define IMPL(n) \ INIT(n); \ int objIdx; \ for (objIdx = 0; objIdx < nobjects; objIdx++) { \ ADDOBJ(objects[objIdx].object, objects[objIdx].offset, objects[objIdx].length, \ objects[objIdx].flags); \ } \ CALL##n; #define DEF_N(x) jlong n##x #define DEF_N1 DEF_N(1) #define DEF_N2 DEF_N1, DEF_N(2) #define DEF_N3 DEF_N2, DEF_N(3) #define DEF_N4 DEF_N3, DEF_N(4) #define DEF_N5 DEF_N4, DEF_N(5) #define DEF_N6 DEF_N5, DEF_N(6) #define DEFINVOKE(n) \ static jlong invoke##n(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, DEF_N##n, ObjectParam* objects, int nobjects) \ { \ IMPL(n); \ } DEFINVOKE(1) DEFINVOKE(2) DEFINVOKE(3) DEFINVOKE(4) DEFINVOKE(5) DEFINVOKE(6) #define DEF_O(x) jobject o##x, jint o##x##flags, jint o##x##off, jint o##x##len #define DEF_O1 DEF_O(1) #define DEF_O2 DEF_O1, DEF_O(2) #define DEF_O3 DEF_O2, DEF_O(3) #define DEF_O4 DEF_O3, DEF_O(4) #define DEF_O5 DEF_O4, DEF_O(5) #define DEF_O6 DEF_O5, DEF_O(6) #define DEF_N(x) jlong n##x #define DEF_N1 DEF_N(1) #define DEF_N2 DEF_N1, DEF_N(2) #define DEF_N3 DEF_N2, DEF_N(3) #define DEF_N4 DEF_N3, DEF_N(4) #define DEF_N5 DEF_N4, DEF_N(5) #define DEF_N6 DEF_N5, DEF_N(6) #define OBJ(x) { o##x, o##x##off, o##x##len, o##x##flags } #define OBJ1 OBJ(1) #define OBJ2 OBJ1, OBJ(2) #define OBJ3 OBJ2, OBJ(3) #define OBJ4 OBJ3, OBJ(4) #define OBJ5 OBJ4, OBJ(5) #define OBJ6 OBJ5, OBJ(6) #define DEFJNI(n, o) \ JNIEXPORT jlong JNICALL \ Java_com_kenai_jffi_Foreign_invokeN##n##O##o(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, DEF_N##n, DEF_O##o) \ { \ ObjectParam objects[] = { OBJ##o }; \ return invoke##n(env, self, ctxAddress, function, N##n, objects, o); \ } DEFJNI(1, 1) DEFJNI(2, 1) DEFJNI(2, 2) DEFJNI(3, 1) DEFJNI(3, 2) DEFJNI(3, 3) DEFJNI(4, 1) DEFJNI(4, 2) DEFJNI(4, 3) DEFJNI(4, 4) DEFJNI(5, 1) DEFJNI(5, 2) DEFJNI(5, 3) DEFJNI(5, 4) DEFJNI(5, 5) DEFJNI(6, 1) DEFJNI(6, 2) DEFJNI(6, 3) DEFJNI(6, 4) DEFJNI(6, 5) DEFJNI(6, 6) jffi-1.2.7/jni/jffi/FaultProtect.c000066400000000000000000000121171247047424400167270ustar00rootroot00000000000000#include "FaultProtect.h" #if FAULT_PROTECT_ENABLED #include #include #include #include #include #include #include #include #include "jffi.h" #include "Exception.h" #ifdef __APPLE__ # define SKIP_FRAME_COUNT (2) #endif struct sigaction jffi_sigsegv_chain; struct sigaction jffi_sigbus_chain; void fill_in_backtrace(FaultData* fdp) { unw_context_t uc; unw_cursor_t c; int i, boff; memset(&uc, 0, sizeof(uc)); memset(&c, 0, sizeof(c)); if (unw_getcontext(&uc) < 0) { abort(); } if (unw_init_local(&c, &uc) < 0) { abort(); } // Skip the signal handler, and the signal trampoline for (i = 0; i < SKIP_FRAME_COUNT; i++) { if (unw_step(&c) <= 0) { break; } } memset(fdp->frame, 0, sizeof(fdp->frame)); fdp->frame_count = 0; boff = 0; do { char fn[256]; unw_word_t off, ip; Dl_info dli; unw_proc_info_t pi; unw_get_reg (&c, UNW_REG_IP, &ip); fdp->frame[fdp->frame_count].addr = (uintptr_t) ip; fdp->frame[fdp->frame_count].procname = (uintptr_t) &fdp->backtrace_buf[boff]; unw_get_proc_name(&c, (char *) fdp->frame[fdp->frame_count].procname, sizeof(fdp->backtrace_buf) - boff, &off); unw_get_proc_info(&c, &pi); boff += strlen((char *) fdp->frame[fdp->frame_count].procname) + 1; fdp->frame[fdp->frame_count].libname = (uintptr_t) &fdp->backtrace_buf[boff]; dladdr((void *)(uintptr_t) ip, &dli); strcpy((char *) (uintptr_t) fdp->frame[fdp->frame_count].libname, dli.dli_fname); boff += strlen((char *) fdp->frame[fdp->frame_count].libname) + 1; fdp->frame_count++; } while (unw_step(&c) > 0); } static void jffi_fault(void) { ThreadData* td = (ThreadData *) pthread_getspecific(jffi_threadDataKey); FaultData* fdp = td->fault_data; td->fault_data = NULL; fill_in_backtrace(fdp); jffi_longjmp(fdp->buf, fdp->sig); // If we get here, we could not unwind the stack - restore the old signal handler, and let it re-fault switch (fdp->sig) { case SIGBUS: sigaction(fdp->sig, &jffi_sigbus_chain, NULL); break; case SIGSEGV: sigaction(fdp->sig, &jffi_sigsegv_chain, NULL); break; } } static void jffi_fault_handler(ThreadData* td, int sig, siginfo_t* si, ucontext_t* uctx) { extern int _jffi_fault_trampoline; FaultData* fdp = td->fault_data; int i, boff; fdp->mcontext = *uctx->uc_mcontext; fdp->sig = sig; #ifdef __x86_64__ uctx->uc_mcontext->__ss.__rax = (uintptr_t) &jffi_fault; uctx->uc_mcontext->__ss.__rdx = uctx->uc_mcontext->__ss.__rip; uctx->uc_mcontext->__ss.__rip = (uintptr_t) &_jffi_fault_trampoline; uctx->uc_mcontext->__ss.__rflags = 0; #elif defined(__i386__) uctx->uc_mcontext->ss.eax = (uintptr_t) &jffi_fault; uctx->uc_mcontext->ss.edx = uctx->uc_mcontext->ss.eip; uctx->uc_mcontext->ss.eip = &_jffi_fault_trampoline; uctx->uc_mcontext->ss.eflags = 0; #else # error "architecture not supported" #endif } void jffi_sigsegv(int sig, siginfo_t *si, void *uctx) { ThreadData* td = (ThreadData *) pthread_getspecific(jffi_threadDataKey); if (td == NULL || td->fault_data == NULL) { (*jffi_sigsegv_chain.sa_sigaction)(sig, si, uctx); } else { jffi_fault_handler(td, sig, si, (ucontext_t *) uctx); } } void jffi_sigbus(int sig, siginfo_t *si, void *uctx) { ThreadData* td = (ThreadData *) pthread_getspecific(jffi_threadDataKey); if (td == NULL || td->fault_data == NULL) { (*jffi_sigbus_chain.sa_sigaction)(sig, si, uctx); } else { jffi_fault_handler(td, sig, si, (ucontext_t *) uctx); } } void jffi_faultException(JNIEnv* env, struct FaultData_* f, int val) { jclass exceptionClass = (*env)->FindClass(env, "com/kenai/jffi/FaultException"); if (exceptionClass != NULL) { jmethodID constructor = (*env)->GetMethodID(env, exceptionClass, "", "(I[J[J[J)V"); if (constructor != NULL) { jlongArray addresses = (*env)->NewLongArray(env, f->frame_count); jlongArray procnames = (*env)->NewLongArray(env, f->frame_count); jlongArray libnames = (*env)->NewLongArray(env, f->frame_count); int i; for (i = 0; i < f->frame_count; i++) { jlong ip = f->frame[i].addr; jlong procname = f->frame[i].procname; jlong libname = f->frame[i].libname; (*env)->SetLongArrayRegion(env, addresses, i, 1, &ip); (*env)->SetLongArrayRegion(env, procnames, i, 1, &procname); (*env)->SetLongArrayRegion(env, libnames, i, 1, &libname); } jobject exc = (*env)->NewObject(env, exceptionClass, constructor, val, addresses, procnames, libnames); if (exc != NULL) (*env)->Throw(env, (jthrowable) exc); } (*env)->DeleteLocalRef(env, exceptionClass); } else { throwException(env, NullPointer, "fault"); } } #endif jffi-1.2.7/jni/jffi/FaultProtect.h000066400000000000000000000067201247047424400167370ustar00rootroot00000000000000/* * Copyright (C) 2012 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef JFFI_FAULTPROTECT_H #define JFFI_FAULTPROTECT_H #include #include #include #if defined(__APPLE__) && (defined(__x86_64__) || defined(__i386__)) && 0 # define FAULT_PROTECT_ENABLED (1) #else # define FAULT_PROTECT_ENABLED (0) #endif typedef struct FaultData_ FaultData; #if FAULT_PROTECT_ENABLED extern struct sigaction jffi_sigsegv_chain; extern struct sigaction jffi_sigbus_chain; extern void jffi_sigsegv(int sig, siginfo_t *si, void *uctx); extern void jffi_sigbus(int sig, siginfo_t *si, void *uctx); #include #include struct FaultData_ { jmp_buf buf; int sig; _STRUCT_MCONTEXT mcontext; struct { uintptr_t addr; uintptr_t procname; uintptr_t libname; } frame[128]; int frame_count; char backtrace_buf[1024]; }; extern int jffi_setjmp(struct FaultData_ *); extern void jffi_longjmp(jmp_buf env, int val); extern void jffi_faultException(JNIEnv* env, struct FaultData_ *, int val); #if defined(__amd64) || defined(__x86_64__) # if defined (__APPLE__) # define JB_SP 1 # define JB_RP 0 # define UNW_REG_EH UNW_X86_64_RAX # endif #else # define JB_SP 1 # define JB_RP 0 # define UNW_REG_EH UNW_X86_EAX #endif #define FAULTPROT_CTX(env, ctx, stmt, fail) do { \ if (likely((ctx->flags & (CALL_CTX_SAVE_ERRNO | CALL_CTX_FAULT_PROT)) == 0)) { \ stmt; \ } else if (likely((ctx->flags & CALL_CTX_FAULT_PROT) == 0)) { \ stmt; \ jffi_save_errno_ctx(ctx); \ } else { \ JNIEnv* volatile env_ = env; \ FaultData fd; \ int val; \ \ if (unlikely((val = jffi_setjmp(&fd)) != 0)) { \ jffi_faultException(env_, &fd, val); \ fail; \ } else { \ ThreadData* td = thread_data_get(); \ td->fault_data = &fd; \ stmt; \ td->fault_data = NULL; \ jffi_save_errno_td(td, ctx); \ } \ } \ } while(0) #else /* fault protection not enabled */ struct FaultData_ { long dummy; }; # define FAULTPROT_CTX(env, ctx, stmt, fail) do { \ stmt; \ SAVE_ERRNO(ctx); \ } while(0) #endif #endif /* JFFI_FAULTPROTECT_H */ jffi-1.2.7/jni/jffi/Foreign.c000066400000000000000000000162201247047424400157030ustar00rootroot00000000000000/* * Copyright (C) 2008-2010 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #ifndef _WIN32 # include #endif #include #include #include "Exception.h" #include "com_kenai_jffi_Foreign.h" #include "com_kenai_jffi_Version.h" #include "jffi.h" #include "FaultProtect.h" #ifndef _WIN32 pthread_key_t jffi_threadDataKey; static void thread_data_free(void *ptr); #endif JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { #ifndef _WIN32 struct sigaction sa; pthread_key_create(&jffi_threadDataKey, thread_data_free); #if FAULT_PROTECT_ENABLED memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = jffi_sigsegv; sa.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &sa, &jffi_sigsegv_chain); sa.sa_sigaction = jffi_sigbus; sigaction(SIGBUS, &sa, &jffi_sigbus_chain); #endif #endif return JNI_VERSION_1_4; } JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved) { #ifndef _WIN32 pthread_key_delete(jffi_threadDataKey); #endif } #ifndef _WIN32 ThreadData* jffi_thread_data_init() { ThreadData* td = calloc(1, sizeof(*td)); pthread_setspecific(jffi_threadDataKey, td); return td; } static void thread_data_free(void *ptr) { ThreadData* td = (ThreadData *) ptr; if (td->attached_vm != NULL) { (*td->attached_vm)->DetachCurrentThread(td->attached_vm); } free(ptr); } #endif /* !_WIN32 */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getVersion(JNIEnv* env, jobject self) { return (com_kenai_jffi_Version_MAJOR << 16) | (com_kenai_jffi_Version_MINOR << 8) | (com_kenai_jffi_Version_MICRO); } /* * Class: com_kenai_jffi_Foreign * Method: init * Signature: ()V * * Initialize any class/method/field ids */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_init(JNIEnv* env, jobject self) { } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getJNIVersion(JNIEnv* env, jobject self) { return (*env)->GetVersion(env); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getJavaVM(JNIEnv *env, jobject self) { JavaVM* vm; (*env)->GetJavaVM(env, &vm); return p2j(vm); } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_fatalError(JNIEnv * env, jobject self, jstring msg) { const char* str = (*env)->GetStringUTFChars(env, msg, NULL); (*env)->FatalError(env, str); (*env)->ReleaseStringUTFChars(env, msg, str); } JNIEXPORT jclass JNICALL Java_com_kenai_jffi_Foreign_defineClass__Ljava_lang_String_2Ljava_lang_Object_2_3BII(JNIEnv *env, jobject self, jstring jname, jobject loader, jbyteArray jbuf, jint off, jint len) { const char* name = NULL; jbyte* buf = NULL; jclass retval = NULL; name = (*env)->GetStringUTFChars(env, jname, NULL); if (name == NULL) { throwException(env, NullPointer, "Invalid name parameter"); goto cleanup; } buf = (*env)->GetByteArrayElements(env, jbuf, NULL); if (buf == NULL) { throwException(env, NullPointer, "Invalid buffer parameter"); goto cleanup; } retval = (*env)->DefineClass(env, name, loader, buf + off, len); cleanup: if (buf != NULL) { (*env)->ReleaseByteArrayElements(env, jbuf, buf, JNI_ABORT); } if (name != NULL) { (*env)->ReleaseStringUTFChars(env, jname, name); } return retval; } JNIEXPORT jclass JNICALL Java_com_kenai_jffi_Foreign_defineClass__Ljava_lang_String_2Ljava_lang_Object_2Ljava_nio_ByteBuffer_2(JNIEnv *env, jobject self, jstring jname, jobject loader, jobject jbuf) { const char* name = NULL; jclass retval = NULL; name = (*env)->GetStringUTFChars(env, jname, NULL); if (name == NULL) { throwException(env, NullPointer, "Invalid name parameter"); goto cleanup; } if (jbuf == NULL) { throwException(env, NullPointer, "Invalid buffer parameter"); goto cleanup; } retval = (*env)->DefineClass(env, name, loader, (*env)->GetDirectBufferAddress(env, jbuf), (*env)->GetDirectBufferCapacity(env, jbuf)); cleanup: if (name != NULL) { (*env)->ReleaseStringUTFChars(env, jname, name); } return retval; } JNIEXPORT jobject JNICALL Java_com_kenai_jffi_Foreign_allocObject(JNIEnv *env, jobject self, jclass klass) { return (*env)->AllocObject(env, klass); } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_registerNatives(JNIEnv *env, jobject self, jclass clazz, jlong methods, jint nmethods) { return (*env)->RegisterNatives(env, clazz, j2p(methods), nmethods); } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_unregisterNatives(JNIEnv *env, jobject self, jclass clazz) { return (*env)->UnregisterNatives(env, clazz); } /* * Determine the cpu type at compile time - useful for MacOSX where the jvm * reports os.arch as 'universal' */ #if defined(__i386__) || defined(__i386) # define CPU "i386" #elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) # define CPU "x86_64" #elif defined(__ppc64__) || defined(__powerpc64__) # define CPU "ppc64" #elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc) # define CPU "ppc" /* Need to check for __sparcv9 first, because __sparc will be defined either way . */ #elif defined(__sparcv9__) || defined(__sparcv9) # define CPU "sparcv9" #elif defined(__sparc__) || defined(__sparc) # define CPU "sparc" #elif defined(__arm__) || defined(__arm) # define CPU "arm" #elif defined(__ia64__) || defined(__ia64) # define CPU "ia64" #elif defined(__mips__) || defined(__mips) # define CPU "mips" #elif defined(__s390__) # define CPU "s390" #else # define CPU "unknown" #endif /* * Class: com_kenai_jffi_Foreign * Method: getArch * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_kenai_jffi_Foreign_getArch(JNIEnv *env, jobject self) { return (*env)->NewStringUTF(env, CPU); } JNIEXPORT jboolean JNICALL Java_com_kenai_jffi_Foreign_isFaultProtectionEnabled(JNIEnv *env , jclass klass) { return FAULT_PROTECT_ENABLED ? JNI_TRUE : JNI_FALSE; } jffi-1.2.7/jni/jffi/Internals.c000066400000000000000000000036111247047424400162510ustar00rootroot00000000000000/* * Copyright (C) 2010 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include "Exception.h" #include "com_kenai_jffi_Foreign.h" #include "LastError.h" #include "CallContext.h" #include "jffi.h" /* * Class: com_kenai_jffi_Foreign * Method: getSaveErrnoFunction * Signature: ()J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getSaveErrnoFunction(JNIEnv *env, jobject self) { return p2j(jffi_save_errno); } /* * Class: com_kenai_jffi_Foreign * Method: getSaveErrnoFunction * Signature: ()J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getSaveErrnoCtxFunction(JNIEnv *env, jobject self) { return p2j(jffi_save_errno_ctx); } jffi-1.2.7/jni/jffi/Invoke.c000066400000000000000000000425041247047424400155510ustar00rootroot00000000000000/* * Copyright (C) 2008-2010 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #if defined (__sun) || defined(_AIX) # include #endif #ifdef _WIN32 # include #endif #include #include #include #include "jffi.h" #include "Exception.h" #include "CallContext.h" #include "Array.h" #include "LastError.h" #include "FaultProtect.h" #include "com_kenai_jffi_Foreign.h" #define PARAM_SIZE (8) #define MAX_STACK_ARRAY (1024) typedef struct Pinned { jobject object; jsize offset; jsize length; int type; } Pinned; # define COPY_ARGS(ctx, src, ffiArgs) do { \ int idx; \ for (idx = 0; idx < (int) ctx->cif.nargs; ++idx) { \ if (unlikely(ctx->cif.arg_types[idx]->type == FFI_TYPE_STRUCT)) { \ ffiArgs[idx] = *(void **) &src[idx * PARAM_SIZE]; \ } else { \ ffiArgs[idx] = &src[idx * PARAM_SIZE]; \ } \ } \ } while (0) # define ARG_BUFFER_SIZE(ctx) ((ctx)->cif.nargs * PARAM_SIZE) static void invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jint objectCount, jint* infoBuffer, jobject* objectBuffer, void* retval); /* * Class: com_kenai_jffi_Foreign * Method: isRawParameterPackingEnabled * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_com_kenai_jffi_Foreign_isRawParameterPackingEnabled(JNIEnv* env, jobject self) { return JNI_FALSE; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayInt32 * Signature: (J[B)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnInt(JNIEnv* env, jclass self, jlong ctxAddress, jlong function, jbyteArray paramBuffer) { FFIValue retval; invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 0, NULL, NULL, &retval); return_int(retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayInt64 * Signature: (J[B)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnLong(JNIEnv* env, jclass self, jlong ctxAddress, jlong function, jbyteArray paramBuffer) { FFIValue retval; invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 0, NULL, NULL, &retval); return retval.s64; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayFloat * Signature: (J[B)F */ JNIEXPORT jfloat JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnFloat(JNIEnv* env, jclass self, jlong ctxAddress, jlong function, jbyteArray paramBuffer) { FFIValue retval; invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 0, NULL, NULL, &retval); return retval.f; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayDouble * Signature: (J[B)D */ JNIEXPORT jdouble JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnDouble(JNIEnv* env, jclass self, jlong ctxAddress, jlong function, jbyteArray paramBuffer) { FFIValue retval; invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 0, NULL, NULL, &retval); return retval.d; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayReturnStruct * Signature: (J[B[B)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnStruct(JNIEnv* env, jclass self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jbyteArray returnBuffer, jint offset) { CallContext* ctx = (CallContext *) j2p(ctxAddress); jbyte* retval = alloca(ctx->cif.rtype->size); invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 0, NULL, NULL, retval); (*env)->SetByteArrayRegion(env, returnBuffer, offset, ctx->cif.rtype->size, retval); } static void invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jint objectCount, jint* infoBuffer, jobject* objectBuffer, void* retval) { CallContext* ctx = (CallContext *) j2p(ctxAddress); void **ffiArgs = { NULL }; Array *arrays = NULL; Pinned *pinned = NULL; int i, arrayCount = 0, pinnedCount = 0, paramBytes = 0; if (unlikely(objectCount > 0)) { arrays = alloca(objectCount * sizeof(Array)); pinned = alloca(objectCount * sizeof(Pinned)); } if (ctx->cif.nargs > 0) { jbyte* tmpBuffer = alloca(ARG_BUFFER_SIZE(ctx)); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ARG_BUFFER_SIZE(ctx), tmpBuffer); ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); COPY_ARGS(ctx, tmpBuffer, ffiArgs); } for (i = 0; i < objectCount; ++i) { int type = infoBuffer[i * 3]; jsize offset = infoBuffer[(i * 3) + 1]; jsize length = infoBuffer[(i * 3) + 2]; jobject object = objectBuffer[i]; int idx = (type & com_kenai_jffi_ObjectBuffer_INDEX_MASK) >> com_kenai_jffi_ObjectBuffer_INDEX_SHIFT; void* ptr; switch (type & com_kenai_jffi_ObjectBuffer_TYPE_MASK & ~com_kenai_jffi_ObjectBuffer_PRIM_MASK) { case com_kenai_jffi_ObjectBuffer_ARRAY: if (unlikely(object == NULL)) { throwException(env, NullPointer, "null object for parameter %d", idx); goto cleanup; } if (unlikely((type & com_kenai_jffi_ObjectBuffer_PINNED) != 0)) { // Record the pinned array, but the actual pinning will be done just before the ffi_call Pinned* p = &pinned[pinnedCount++]; p->object = object; p->offset = offset; p->length = length; p->type = type; ptr = NULL; } else if (likely(length < MAX_STACK_ARRAY)) { ptr = alloca(jffi_arraySize(length + 1, type)); if (unlikely(jffi_getArrayBuffer(env, object, offset, length, type, &arrays[arrayCount], ptr) == NULL)) { goto cleanup; } ++arrayCount; } else { ptr = jffi_getArrayHeap(env, object, offset, length, type, &arrays[arrayCount]); if (unlikely(ptr == NULL)) { goto cleanup; } ++arrayCount; } break; case com_kenai_jffi_ObjectBuffer_BUFFER: if (unlikely(object == NULL)) { throwException(env, NullPointer, "null object for parameter %d", idx); goto cleanup; } ptr = (*env)->GetDirectBufferAddress(env, object); if (unlikely(ptr == NULL)) { throwException(env, NullPointer, "null direct buffer address for parameter %d", idx); goto cleanup; } ptr = ((char *) ptr + offset); break; case com_kenai_jffi_ObjectBuffer_JNI: switch (type & com_kenai_jffi_ObjectBuffer_TYPE_MASK) { case com_kenai_jffi_ObjectBuffer_JNIENV: ptr = env; break; case com_kenai_jffi_ObjectBuffer_JNIOBJECT: ptr = (void *) object; break; default: throwException(env, IllegalArgument, "Unsupported object type: %#x", type & com_kenai_jffi_ObjectBuffer_TYPE_MASK); goto cleanup; } break; default: throwException(env, IllegalArgument, "Unsupported object type: %#x", type & com_kenai_jffi_ObjectBuffer_TYPE_MASK); goto cleanup; } if (likely(ctx->cif.arg_types[idx]->type == FFI_TYPE_POINTER)) { *((void **) ffiArgs[idx]) = ptr; } else { ffiArgs[idx] = ptr; } } // // Pin all the arrays just before calling the native function. // // Although hotspot allows it, other JVMs do not allow JNI operations // once any array has been pinned, so pinning must be done last, just before // the native function is called. // for (i = 0; i < pinnedCount; i++) { Pinned* p = &pinned[i]; Array* ary = &arrays[arrayCount]; int idx = (p->type & com_kenai_jffi_ObjectBuffer_INDEX_MASK) >> com_kenai_jffi_ObjectBuffer_INDEX_SHIFT; void* ptr = jffi_getArrayCritical(env, p->object, p->offset, p->length, p->type, &arrays[arrayCount]); if (unlikely(ptr == NULL)) { goto cleanup; } if (likely(ctx->cif.arg_types[idx]->type == FFI_TYPE_POINTER)) { *((void **) ffiArgs[idx]) = ptr; } else { ffiArgs[idx] = ptr; } ++arrayCount; } FAULTPROT_CTX(env, ctx, ffi_call(&ctx->cif, FFI_FN(j2p(function)), retval, ffiArgs), ); cleanup: /* Release any array backing memory */ RELEASE_ARRAYS(env, arrays, arrayCount); } static void invokeArrayWithObjects(JNIEnv* env, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray, void* retval) { jint* infoBuffer = alloca(objectCount * sizeof(jint) * 3); jobject* objectBuffer = alloca(objectCount * sizeof(jobject)); int i; (*env)->GetIntArrayRegion(env, objectInfo, 0, objectCount * 3, infoBuffer); for (i = 0; i < objectCount; ++i) { objectBuffer[i] = (*env)->GetObjectArrayElement(env, objectArray, i); } invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, objectCount, infoBuffer, objectBuffer, retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsInt32 * Signature: (J[B[I[Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsInt32(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray) { FFIValue retval; invokeArrayWithObjects(env, ctxAddress, function, paramBuffer, objectCount, objectInfo, objectArray, &retval); return_int(retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayO1Int32 * Signature: (J[BILjava/lang/Object;I)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeArrayO1Int32(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jobject o1, jint o1info, jint o1off, jint o1len) { FFIValue retval; jint info[] = { o1info, o1off, o1len }; jobject objects[] = { o1 }; invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 1, info, objects, &retval); return_int(retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayO2Int32 * Signature: (J[BLjava/lang/Object;IIILjava/lang/Object;III)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeArrayO2Int32(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jobject o1, jint o1info, jint o1off, jint o1len, jobject o2, jint o2info, jint o2off, jint o2len) { FFIValue retval; jint info[] = { o1info, o1off, o1len, o2info, o2off, o2len }; jobject objects[] = { o1, o2 }; invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 2, info, objects, &retval); return_int(retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsInt64 * Signature: (J[BI[I[Ljava/lang/Object;)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsInt64(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray) { FFIValue retval; invokeArrayWithObjects(env, ctxAddress, function, paramBuffer, objectCount, objectInfo, objectArray, &retval); return retval.s64; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayO1Int64 * Signature: (J[BLjava/lang/Object;III)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeArrayO1Int64(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jobject o1, jint o1info, jint o1off, jint o1len) { FFIValue retval; jint info[] = { o1info, o1off, o1len }; jobject objects[] = { o1 }; invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 1, info, objects, &retval); return retval.j; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayO2Int64 * Signature: (J[BLjava/lang/Object;IIILjava/lang/Object;III)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeArrayO2Int64(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jobject o1, jint o1info, jint o1off, jint o1len, jobject o2, jint o2info, jint o2off, jint o2len) { FFIValue retval; jint info[] = { o1info, o1off, o1len, o2info, o2off, o2len }; jobject objects[] = { o1, o2 }; invokeArrayWithObjects_(env, ctxAddress, function, paramBuffer, 2, info, objects, &retval); return retval.j; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsFloat * Signature: (J[BI[I[Ljava/lang/Object;)F */ JNIEXPORT jfloat JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsFloat(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray) { FFIValue retval; invokeArrayWithObjects(env, ctxAddress, function, paramBuffer, objectCount, objectInfo, objectArray, &retval); return retval.f; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsDouble * Signature: (J[BI[I[Ljava/lang/Object;)D */ JNIEXPORT jdouble JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsDouble(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray) { FFIValue retval; invokeArrayWithObjects(env, ctxAddress, function, paramBuffer, objectCount, objectInfo, objectArray, &retval); return retval.d; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsReturnStruct * Signature: (J[BI[I[Ljava/lang/Object;[BI)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsReturnStruct(JNIEnv* env, jobject self, jlong ctxAddress, jlong function, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray, jbyteArray returnBuffer, jint returnBufferOffset) { CallContext* ctx = (CallContext *) j2p(ctxAddress); jbyte* retval = alloca(ctx->cif.rtype->size); invokeArrayWithObjects(env, ctxAddress, function, paramBuffer, objectCount, objectInfo, objectArray, retval); (*env)->SetByteArrayRegion(env, returnBuffer, returnBufferOffset, ctx->cif.rtype->size, retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokePointerParameterArray * Signature: (JJ[J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_invokePointerParameterArray(JNIEnv *env, jobject self, jlong ctxAddress, jlong function, jlong returnBuffer, jlongArray parameterArray) { CallContext* ctx = (CallContext *) j2p(ctxAddress); int parameterCount; jlong* params = NULL; void** ffiArgs = NULL; int i; if (unlikely(ctxAddress == 0LL)) { throwException(env, NullPointer, "context address is null"); return; } if (unlikely(returnBuffer == 0LL)) { throwException(env, NullPointer, "result buffer is null"); return; } if (unlikely(parameterArray == NULL)) { throwException(env, NullPointer, "parameter array is null"); return; } parameterCount = (*env)->GetArrayLength(env, parameterArray); if (parameterCount > 0) { params = alloca(parameterCount * sizeof(jlong)); ffiArgs = alloca(parameterCount * sizeof(void *)); (*env)->GetLongArrayRegion(env, parameterArray, 0, parameterCount, params); for (i = 0; i < parameterCount; ++i) { ffiArgs[i] = j2p(params[i]); } } ffi_call(&ctx->cif, FFI_FN(j2p(function)), j2p(returnBuffer), ffiArgs); } jffi-1.2.7/jni/jffi/LastError.c000066400000000000000000000057551247047424400162420ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #ifdef _WIN32 # include #endif #include #include "LastError.h" #include "CallContext.h" #if defined(_WIN32) static __thread int last_error = 0; #endif /* * Class: com_kenai_jffi_Foreign * Method: getLastError * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getLastError(JNIEnv* env, jobject self) { #ifdef _WIN32 // printf("Getting ERRNO: %d on thread %d\n", last_error, (int)GetCurrentThreadId()); return last_error; #else return thread_data_get()->error; #endif } /* * Class: com_kenai_jffi_Foreign * Method: setLastError * Signature: (I)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_setLastError(JNIEnv* env, jobject self, jint value) { #ifdef _WIN32 // printf("Setting ERRNO: %d on thread %d\n", value, (int)GetCurrentThreadId()); SetLastError(value); last_error = value; #else thread_data_get()->error = errno = value; #endif } void jffi_save_errno(void) { #ifdef _WIN32 last_error = GetLastError(); // printf("JFFI Saving ERRNO: %d on thread %d\n", last_error, (int)GetCurrentThreadId()); #else thread_data_get()->error = errno; #endif } void jffi_save_errno_ctx(CallContext* ctx) { #ifdef _WIN32 if (unlikely(ctx->error_fn != NULL)) { last_error = (*ctx->error_fn)(); } else { last_error = GetLastError(); } #else if (unlikely(ctx->error_fn != NULL)) { thread_data_get()->error = (*ctx->error_fn)(); } else { thread_data_get()->error = errno; } #endif } #ifndef _WIN32 void jffi_save_errno_td(ThreadData* td, CallContext* ctx) { if (unlikely(ctx->error_fn != NULL)) { td->error = (*ctx->error_fn)(); } else { td->error = errno; } } #endif jffi-1.2.7/jni/jffi/LastError.h000066400000000000000000000030151247047424400162320ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef JFFI_LASTERRROR_H #define JFFI_LASTERRROR_H #include "jffi.h" #include "CallContext.h" extern void jffi_save_errno(void); #ifndef _WIN32 extern void jffi_save_errno_td(ThreadData* td, CallContext* ctx); #endif #endif /* JFFI_LASTERRROR_H */ jffi-1.2.7/jni/jffi/Library.c000066400000000000000000000141411247047424400157160ustar00rootroot00000000000000/* * Copyright (C) 2008-2010 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include #include #if defined(_WIN32) || defined(__WIN32__) # include # include #else # include #endif #if defined (__sun) || defined(_AIX) # include #endif #include #include #include "jffi.h" #include "Exception.h" #include "com_kenai_jffi_Foreign.h" #if defined(_WIN32) || defined(__WIN32__) static void* dl_open(const char* name, int flags); static void dl_error(char* buf, int size); #define dl_sym(handle, name) GetProcAddress(handle, name) #define dl_close(handle) FreeLibrary(handle) enum { RTLD_LAZY=1, RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL }; #else # define dl_open(name, flags) dlopen(name, flags != 0 ? flags : (RTLD_LAZY | RTLD_LOCAL)) # define dl_error(buf, size) do { \ const char *e = dlerror(); snprintf(buf, size, "%s", e ? e : "unknown"); \ } while(0) # define dl_sym(handle, name) dlsym(handle, name) # define dl_close(handle) dlclose(handle) #ifndef RTLD_LOCAL # define RTLD_LOCAL 8 #endif #endif static int getMultibyteString(JNIEnv* env, char* dst, jstring jstr, int n); static int getWideString(JNIEnv* env, wchar_t* dst, jstring jstr, int n); /* * Class: com_kenai_jffi_Foreign * Method: dlopen * Signature: (Ljava/lang/String;I)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_dlopen(JNIEnv* env, jobject self, jstring jPath, jint jFlags) { #ifdef _WIN32 if (jPath == NULL) { return p2j(GetModuleHandle(NULL)); } else { wchar_t path[PATH_MAX]; getWideString(env, path, jPath, sizeof(path) / sizeof(path[0])); return p2j(LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)); } #else char path_[PATH_MAX]; const char* path = NULL; // Handle dlopen(NULL, flags); void* handle = NULL; int flags = 0; #define F(x) (jFlags & com_kenai_jffi_Foreign_RTLD_##x) != 0 ? RTLD_##x : 0; flags |= F(LAZY); flags |= F(GLOBAL); flags |= F(LOCAL); flags |= F(NOW); #undef F #ifdef _AIX flags |= RTLD_MEMBER; // Needed for AIX #endif if (jPath != NULL) { path = path_; getMultibyteString(env, path_, jPath, sizeof(path_)); } handle = dl_open(path, flags); if (handle == NULL) { char errbuf[1024] = { 0 }; dl_error(errbuf, sizeof(errbuf) - 1); throwException(env, UnsatisfiedLink, "%s", errbuf); } return p2j(handle); #endif } /* * Class: com_googlecode_jffi_NativeLibrary * Method: dlclose * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_dlclose(JNIEnv* env, jclass cls, jlong handle) { dl_close(j2p(handle)); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_dlsym(JNIEnv* env, jclass cls, jlong handle, jstring jstr) { char sym[1024]; void* addr; getMultibyteString(env, sym, jstr, sizeof(sym)); #ifndef _WIN32 dlerror(); // clear any errors #endif addr = dl_sym(j2p(handle), sym); if (addr == NULL) { char errbuf[1024] = { 0 }; dl_error(errbuf, sizeof(errbuf) - 1); throwException(env, UnsatisfiedLink, "%s", errbuf); } return p2j(addr); } /* * Class: com_kenai_jffi_Foreign * Method: dlerror * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_kenai_jffi_Foreign_dlerror(JNIEnv* env, jobject self) { char errbuf[1024] = { 0 }; dl_error(errbuf, sizeof(errbuf) - 1); return (*env)->NewStringUTF(env, errbuf); } #if defined(_WIN32) || defined(__WIN32__) static void* dl_open(const char* name, int flags) { if (name == NULL) { return GetModuleHandle(NULL); } else { return LoadLibraryEx(name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); } } static void dl_error(char* buf, int size) { FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buf, size, NULL); } #endif static int getWideString(JNIEnv* env, wchar_t* dst, jstring src, int n) { const jchar* jstr = NULL; int len, i; if (src != NULL) { jstr = (*env)->GetStringChars(env, src, NULL); } len = (*env)->GetStringLength(env, src); if (len > (n - 1)) len = n - 1; for (i = 0; i < len; ++i) { dst[i] = (wchar_t) jstr[i]; } dst[len] = (wchar_t) 0; if (jstr != NULL) { (*env)->ReleaseStringChars(env, src, jstr); } return len; } static int getMultibyteString(JNIEnv* env, char* dst, jstring src, int n) { wchar_t* wstr = NULL; const jchar* jstr = NULL; int len, i; if (src != NULL) { jstr = (*env)->GetStringChars(env, src, NULL); } len = (*env)->GetStringLength(env, src); wstr = alloca(sizeof(wchar_t) * (len + 1)); for (i = 0; i < len; ++i) { wstr[i] = (wchar_t) jstr[i]; } wstr[len] = (wchar_t) 0; if (jstr != NULL) { (*env)->ReleaseStringChars(env, src, jstr); } return wcstombs(dst, wstr, n); } jffi-1.2.7/jni/jffi/LongDouble.c000066400000000000000000000115301247047424400163430ustar00rootroot00000000000000/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #ifdef __sun # include #endif #include #include #include #include "jffi.h" #include "Exception.h" #include "com_kenai_jffi_Foreign.h" static void jffi_encodeLongDouble(JNIEnv *env, long double ld, jbyteArray array, jint arrayOffset, jint arrayLength) { if (arrayLength != sizeof(ld)) { throwException(env, Runtime, "array size != sizeof(long double)"); return; } (*env)->SetByteArrayRegion(env, array, arrayOffset, arrayLength, (jbyte *) &ld); } static long double jffi_decodeLongDouble(JNIEnv *env, jbyteArray array, jint arrayOffset, jint arrayLength) { long double ld; if (arrayLength != sizeof(ld)) { throwException(env, Runtime, "array size != sizeof(long double)"); return 0.0; } (*env)->GetByteArrayRegion(env, array, arrayOffset, arrayLength, (jbyte *) &ld); return ld; } /* * Class: com_kenai_jffi_Foreign * Method: longDoubleFromEngineeringString * Signature: (Ljava/lang/String;[BII)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_longDoubleFromString(JNIEnv *env, jobject self, jstring str, jbyteArray array, jint arrayOffset, jint arrayLength) { long double ld; char* tmp; jsize len; len = (*env)->GetStringUTFLength(env, str); tmp = alloca(len + 1); (*env)->GetStringUTFRegion(env, str, 0, len, tmp); ld = strtold(tmp, NULL); jffi_encodeLongDouble(env, ld, array, arrayOffset, arrayLength); } static inline jstring jffi_longDoubleToString(JNIEnv *env, jbyteArray array, jint arrayOffset, jint arrayLength, const char * const fmt) { char tmp[256]; sprintf(tmp, fmt, jffi_decodeLongDouble(env, array, arrayOffset, arrayLength)); return (*env)->NewStringUTF(env, tmp); } /* * Class: com_kenai_jffi_Foreign * Method: longDoubleToEngineeringString * Signature: ([BII)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_kenai_jffi_Foreign_longDoubleToEngineeringString(JNIEnv *env, jobject self, jbyteArray array, jint arrayOffset, jint arrayLength) { return jffi_longDoubleToString(env, array, arrayOffset, arrayLength, "%.35Le"); } /* * Class: com_kenai_jffi_Foreign * Method: longDoubleToPlainString * Signature: ([BII)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_kenai_jffi_Foreign_longDoubleToPlainString(JNIEnv *env, jobject self, jbyteArray array, jint arrayOffset, jint arrayLength) { return jffi_longDoubleToString(env, array, arrayOffset, arrayLength, "%.35Lf"); } /* * Class: com_kenai_jffi_Foreign * Method: longDoubleToString * Signature: ([BII)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_kenai_jffi_Foreign_longDoubleToString(JNIEnv *env, jobject self, jbyteArray array, jint arrayOffset, jint arrayLength) { return jffi_longDoubleToString(env, array, arrayOffset, arrayLength, "%.35Lg"); } /* * Class: com_kenai_jffi_Foreign * Method: longDoubleFromDouble * Signature: (D[BII)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_longDoubleFromDouble(JNIEnv *env, jobject self, jdouble doubleValue, jbyteArray array, jint arrayOffset, jint arrayLength) { jffi_encodeLongDouble(env, doubleValue, array, arrayOffset, arrayLength); } /* * Class: com_kenai_jffi_Foreign * Method: longDoubleToDouble * Signature: ([BII)D */ JNIEXPORT jdouble JNICALL Java_com_kenai_jffi_Foreign_longDoubleToDouble(JNIEnv *env, jobject self, jbyteArray array, jint arrayOffset, jint arrayLength) { return jffi_decodeLongDouble(env, array, arrayOffset, arrayLength); } jffi-1.2.7/jni/jffi/Memory.c000066400000000000000000000115521247047424400155650ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #ifndef _WIN32 # include #else # include # include # include #endif #include #include "Exception.h" #include "LastError.h" #include "com_kenai_jffi_Foreign.h" #include "jffi.h" /* * Class: com_kenai_jffi_Foreign * Method: pageSize * Signature: ()J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_pageSize(JNIEnv *env, jobject self) { #ifndef _WIN32 return sysconf(_SC_PAGESIZE); #else SYSTEM_INFO si; GetSystemInfo(&si); return si.dwPageSize; #endif } #ifndef _WIN32 static int PROT(int p); static int FLAGS(int f); /* * Class: com_kenai_jffi_Foreign * Method: mmap * Signature: (JJIIIJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_mmap(JNIEnv *env, jobject self, jlong addr, jlong len, jint prot, jint flags, jint fd, jlong off) { caddr_t result; result = mmap(j2p(addr), len, PROT(prot), FLAGS(flags), fd, off); if (unlikely(result == (caddr_t) -1)) { jffi_save_errno(); return -1; } return p2j(result); } /* * Class: com_kenai_jffi_Foreign * Method: munmap * Signature: (JJ)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_munmap(JNIEnv *env, jobject self, jlong addr, jlong len) { int result = munmap(j2p(addr), len); if (unlikely(result != 0)) { jffi_save_errno(); return -1; } return 0; } /* * Class: com_kenai_jffi_Foreign * Method: mprotect * Signature: (JJI)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_mprotect(JNIEnv *env, jobject self, jlong addr, jlong len, jint prot) { int result = mprotect(j2p(addr), len, PROT(prot)); if (unlikely(result != 0)) { jffi_save_errno(); return -1; } return 0; } static int PROT(int p) { int n = 0; n |= ((p & com_kenai_jffi_Foreign_PROT_NONE) != 0) ? PROT_NONE : 0; n |= ((p & com_kenai_jffi_Foreign_PROT_READ) != 0) ? PROT_READ : 0; n |= ((p & com_kenai_jffi_Foreign_PROT_WRITE) != 0) ? PROT_WRITE : 0; n |= ((p & com_kenai_jffi_Foreign_PROT_EXEC) != 0) ? PROT_EXEC : 0; return n; } static int FLAGS(int j) { int m = 0; #define M(x) m |= ((j & com_kenai_jffi_Foreign_MAP_##x) != 0) ? MAP_##x : 0 M(FIXED); M(SHARED); M(PRIVATE); #ifdef MAP_NORESERVE M(NORESERVE); #endif M(ANON); #ifdef MAP_ALIGN M(ALIGN); #endif #ifdef MAP_TEXT M(TEXT); #endif return m; } #else /* _WIN32 */ /* * Class: com_kenai_jffi_Foreign * Method: VirtualAlloc * Signature: (JIII)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_VirtualAlloc(JNIEnv *env, jobject self, jlong addr, jint size, jint flags, jint prot) { void* ptr = VirtualAlloc(j2p(addr), size, flags, prot); if (unlikely(ptr == NULL)) { jffi_save_errno(); return 0; } return p2j(ptr); } /* * Class: com_kenai_jffi_Foreign * Method: VirtualFree * Signature: (JI)Z */ JNIEXPORT jboolean JNICALL Java_com_kenai_jffi_Foreign_VirtualFree(JNIEnv *env, jobject self, jlong addr, jint size, jint flags) { if (!VirtualFree(j2p(addr), size, flags)) { jffi_save_errno(); return JNI_FALSE; } return JNI_TRUE; } /* * Class: com_kenai_jffi_Foreign * Method: VirtualProtect * Signature: (JII)Z */ JNIEXPORT jboolean JNICALL Java_com_kenai_jffi_Foreign_VirtualProtect(JNIEnv *env, jobject self, jlong addr, jint size, jint prot) { DWORD oldprot; if (!VirtualProtect(j2p(addr), size, prot, &oldprot)) { jffi_save_errno(); return JNI_FALSE; } return JNI_TRUE; } #endif /* !_WIN32 */ jffi-1.2.7/jni/jffi/MemoryIO.c000066400000000000000000000322441247047424400160160ustar00rootroot00000000000000/* * Copyright (C) 2007 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include #include #include #include #include "jffi.h" #include "FaultProtect.h" #include "com_kenai_jffi_Foreign.h" #if FAULT_PROTECT_ENABLED # define PROT(stmt, rval) do { \ JNIEnv* volatile env_ = env; \ FaultData fd; \ int val; \ if (unlikely((val = jffi_setjmp(&fd)) != 0)) { \ jffi_faultException(env_, &fd, val); \ return rval; \ } else { \ ThreadData* td = thread_data_get(); \ td->fault_data = &fd; \ stmt; \ td->fault_data = NULL; \ } \ } while (0) #else # define PROT(stmt, rval) do { stmt; } while(0) #endif #ifndef MIN # define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif static void putArrayChecked(JNIEnv* env, jlong address, jobject obj, jint offset, jint length, int typeSize, void (JNICALL *get)(JNIEnv *env, jobject array, jsize start, jsize l, void *buf)); static void getArrayChecked(JNIEnv* env, jlong address, jobject obj, jint offset, jint length, int typeSize, void (JNICALL *put)(JNIEnv *env, jobject array, jsize start, jsize l, const void *buf)); #define GET(JTYPE, NTYPE) JNIEXPORT NTYPE JNICALL \ Java_com_kenai_jffi_Foreign_get##JTYPE(JNIEnv* env, jobject self, jlong address) \ { NTYPE tmp; memcpy(&tmp, j2p(address), sizeof(tmp)); return tmp; } \ JNIEXPORT NTYPE JNICALL \ Java_com_kenai_jffi_Foreign_get##JTYPE##Checked(JNIEnv* env, jobject self, jlong address) \ { NTYPE tmp; PROT(memcpy(&tmp, j2p(address), sizeof(tmp)), 0); return tmp; } #define PUT(JTYPE, NTYPE) \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_put##JTYPE(JNIEnv *env, jobject self, jlong address, NTYPE value) \ { memcpy(j2p(address), &value, sizeof(value)); } \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_put##JTYPE##Checked(JNIEnv *env, jobject self, jlong address, NTYPE value) \ { PROT(memcpy(j2p(address), &value, sizeof(value)),); } #define COPY(JTYPE, NTYPE) \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_put##JTYPE##Array(JNIEnv* env, jobject unsafe, jlong address, jobject obj, jint offset, jint length) \ { \ (*env)->Get##JTYPE##ArrayRegion(env, obj, offset, length, (NTYPE *) j2p(address)); \ } \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_put##JTYPE##ArrayChecked(JNIEnv* env, jobject unsafe, jlong address, jobject obj, jint offset, jint length) \ { \ putArrayChecked(env, address, obj, offset, length, sizeof(NTYPE), \ (void (JNICALL *)(JNIEnv *env, jobject array, jsize start, jsize l, void *buf)) (*env)->Get##JTYPE##ArrayRegion); \ } \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_get##JTYPE##Array(JNIEnv* env, jobject unsafe, jlong address, jobject obj, jint offset, jint length) \ { \ (*env)->Set##JTYPE##ArrayRegion(env, obj, offset, length, (NTYPE *) j2p(address)); \ } \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_get##JTYPE##ArrayChecked(JNIEnv* env, jobject unsafe, jlong address, jobject obj, jint offset, jint length) \ { \ getArrayChecked(env, address, obj, offset, length, sizeof(NTYPE), \ (void (JNICALL *)(JNIEnv *env, jobject array, jsize start, jsize l, const void *)) (*env)->Set##JTYPE##ArrayRegion); \ } static inline void copy(void* dst, const void* src, int len) { int i; for (i = 0; i < len; i++) *((char *) dst + i) = *((const char *) src + i); } static void putArrayChecked(JNIEnv* env, jlong address, jobject obj, jint offset, jint length, int typeSize, void (JNICALL *get)(JNIEnv *env, jobject array, jsize start, jsize l, void *buf)) { jint copyOff = 0; PROT(while (copyOff < length) { jbyte tmp[4096]; int copyLen = MIN((int) sizeof(tmp) / typeSize, length - copyOff); (*get)(env, obj, offset + copyOff, copyLen, tmp); copy(j2p(address + (copyOff * typeSize)), tmp, copyLen * typeSize); copyOff += copyLen; },); } static void getArrayChecked(JNIEnv* env, jlong address, jobject obj, jint offset, jint length, int typeSize, void (JNICALL *put)(JNIEnv *env, jobject array, jsize start, jsize l, const void *buf)) { jint copyOff = 0; PROT(while (copyOff < length) { jbyte tmp[4096]; int copyLen = MIN((int) sizeof(tmp) / typeSize, length - copyOff); copy(tmp, j2p(address + (copyOff * typeSize)), copyLen * typeSize); (*put)(env, obj, offset + copyOff, copyLen, tmp); copyOff += copyLen; },); } #define UNSAFE(J, N) GET(J, N) PUT(J, N) COPY(J, N) UNSAFE(Byte, jbyte); UNSAFE(Char, jchar); UNSAFE(Boolean, jboolean); UNSAFE(Short, jshort); UNSAFE(Int, jint); UNSAFE(Long, jlong); UNSAFE(Float, jfloat); UNSAFE(Double, jdouble); /* * Class: com_googlecode_jffi_JNIUnsafe * Method: getAddress * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getAddress(JNIEnv* ev, jobject self, jlong address) { void* tmp; memcpy(&tmp, j2p(address), sizeof(tmp)); return p2j(tmp); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getAddressChecked(JNIEnv* env, jobject self, jlong address) { void* tmp; PROT(memcpy(&tmp, j2p(address), sizeof(tmp)), 0); return p2j(tmp); } /* * Class: com_googlecode_jffi_JNIUnsafe * Method: putAddress * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_putAddress(JNIEnv* env, jobject self, jlong address, jlong value) { void* tmp = j2p(value); memcpy(j2p(address), &tmp, sizeof(tmp)); } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_putAddressChecked(JNIEnv* env, jobject self, jlong address, jlong value) { void* tmp = j2p(value); PROT(memcpy(j2p(address), &tmp, sizeof(tmp)),); } /* * Class: com_googlecode_jffi_Unsafe_JNIUnsafe * Method: setMemory * Signature: (JJB)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_setMemory(JNIEnv* env, jobject self, jlong address, jlong size, jbyte value) { memset(j2p(address), value, size); } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_setMemoryChecked(JNIEnv* env, jobject self, jlong address, jlong size, jbyte value) { PROT(memset(j2p(address), value, size),); } /* * Class: com_googlecode_jffi_lowlevel_Unsafe_JNIUnsafe * Method: copyMemory * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_copyMemory(JNIEnv* env, jobject self, jlong src, jlong dst, jlong size) { memcpy(j2p(dst), j2p(src), size); } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_copyMemoryChecked(JNIEnv* env, jobject self, jlong src, jlong dst, jlong size) { PROT(memcpy(j2p(dst), j2p(src), size),); } /* * Class: com_googlecode_jffi_lowlevel_Unsafe * Method: memchr * Signature: (JIJ)I */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_memchr(JNIEnv* env, jobject self, jlong address, jint c, jlong maxlen) { return p2j(memchr(j2p(address), c, maxlen)); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_memchrChecked(JNIEnv* env, jobject self, jlong address, jint c, jlong maxlen) { PROT(return p2j(memchr(j2p(address), c, maxlen)), 0); } /* * Class: com_kenai_jffi_Foreign * Method: memmove * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_memmove(JNIEnv* env, jobject self, jlong dst, jlong src, jlong size) { memmove(j2p(dst), j2p(src), size); } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_memmoveChecked(JNIEnv* env, jobject self, jlong dst, jlong src, jlong size) { PROT(memmove(j2p(dst), j2p(src), size),); } /* * Class: com_kenai_jffi_Foreign * Method: memcpy * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_memcpy(JNIEnv* env, jobject self, jlong dst, jlong src, jlong size) { memcpy(j2p(dst), j2p(src), size); } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_memcpyChecked(JNIEnv* env, jobject self, jlong dst, jlong src, jlong size) { PROT(memcpy(j2p(dst), j2p(src), size), ); } /* * Class: com_kenai_jffi_Foreign * Method: strlen * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_strlen(JNIEnv* env, jobject self, jlong address) { return (jlong) strlen(j2p(address)); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_strlenChecked(JNIEnv* env, jobject self, jlong address) { PROT(return (jlong) strlen(j2p(address)), 0); } /* * Class: com_kenai_jffi_Foreign * Method: getUTF8StringAsBytes * Signature: (J)[B */ JNIEXPORT jbyteArray JNICALL Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArray__J(JNIEnv* env, jobject self, jlong address) { const char* str = (const char*) j2p(address); int len = strlen(str); jbyteArray bytes = (*env)->NewByteArray(env, len); (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) str); return bytes; } JNIEXPORT jbyteArray JNICALL Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArrayChecked__J(JNIEnv* env, jobject self, jlong address) { const char* str = (const char*) j2p(address); int len; // Just protecting the strlen against segfault should be sufficient PROT(len = strlen(str), NULL); jbyteArray bytes = (*env)->NewByteArray(env, len); (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) str); return bytes; } /* * Class: com_kenai_jffi_Foreign * Method: getZeroTerminatedByteArray * Signature: (JI)[B */ JNIEXPORT jbyteArray JNICALL Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArray__JI(JNIEnv* env, jobject self, jlong address, jint maxlen) { const char *str = (const char*) j2p(address), *zp; jsize len = ((zp = memchr(str, 0, maxlen)) != NULL) ? zp - str : maxlen; jbyteArray bytes = (*env)->NewByteArray(env, len); (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) str); return bytes; } JNIEXPORT jbyteArray JNICALL Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArrayChecked__JI(JNIEnv* env, jobject self, jlong address, jint maxlen) { const char *str = (const char*) j2p(address), *zp; jsize len; PROT(zp = memchr(str, 0, maxlen), NULL); len = zp != NULL ? zp - str : maxlen; jbyteArray bytes = (*env)->NewByteArray(env, len); (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) str); return bytes; } /* * Class: com_kenai_jffi_Foreign * Method: putZeroTerminatedByteArray * Signature: (J[BII)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_putZeroTerminatedByteArray(JNIEnv *env, jobject self, jlong address, jbyteArray data, jint offset, jint length) { (*env)->GetByteArrayRegion(env, data, offset, length, (jbyte *)j2p(address)); *((char *) (uintptr_t) address + length) = '\0'; } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_putZeroTerminatedByteArrayChecked(JNIEnv *env, jobject self, jlong address, jbyteArray data, jint offset, jint length) { char* cp = (char *) (uintptr_t) address; PROT({ *cp = 0; *(cp + length) ='\0';},); (*env)->GetByteArrayRegion(env, data, offset, length, (jbyte *)j2p(address)); } /* * Class: com_kenai_jffi_Foreign * Method: allocateMemory * Signature: (JZ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_allocateMemory(JNIEnv* env, jobject self, jlong size, jboolean clear) { void* memory = malloc(size); if (memory != NULL && clear != JNI_FALSE) { memset(memory, 0, size); } return p2j(memory); } /* * Class: com_kenai_jffi_Foreign * Method: freeMemory * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeMemory(JNIEnv* env, jobject self, jlong address) { free(j2p(address)); } /* * Class: com_kenai_jffi_Foreign * Method: newDirectByteBuffer * Signature: (I)Ljava/nio/ByteBuffer; */ JNIEXPORT jobject JNICALL Java_com_kenai_jffi_Foreign_newDirectByteBuffer(JNIEnv* env, jobject self, jlong address, jint capacity) { return (*env)->NewDirectByteBuffer(env, j2p(address), capacity); } /* * Class: com_kenai_jffi_Foreign * Method: getDirectBufferAddress * Signature: (Lcom/kenai/jffi/Closure/Buffer;)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getDirectBufferAddress(JNIEnv* env, jobject self, jobject buffer) { return p2j((*env)->GetDirectBufferAddress(env, buffer)); } jffi-1.2.7/jni/jffi/MemoryUtil.c000066400000000000000000000050061247047424400164200ustar00rootroot00000000000000/* * Copyright (C) 2007, 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #ifndef _WIN32 # include #endif #include #include #include #include #ifndef _WIN32 # include #else # include #endif #include #include "MemoryUtil.h" int jffi_getPageSize(void) { #ifdef _WIN32 SYSTEM_INFO si; GetSystemInfo(&si); return si.dwPageSize; #else return sysconf(_SC_PAGESIZE); #endif } void* jffi_allocatePages(int npages) { #ifdef _WIN32 return VirtualAlloc(NULL, npages * jffi_getPageSize(), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); #else caddr_t memory = mmap(NULL, npages * jffi_getPageSize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); return (memory != (caddr_t) -1) ? memory : NULL; #endif } bool jffi_freePages(void *addr, int npages) { #ifdef _WIN32 return VirtualFree(addr, 0, MEM_RELEASE); #else return munmap(addr, npages * jffi_getPageSize()) == 0; #endif } bool jffi_makePagesExecutable(void* memory, int npages) { #ifdef _WIN32 DWORD oldProtect; return VirtualProtect(memory, npages * jffi_getPageSize(), PAGE_EXECUTE_READ, &oldProtect); #else return mprotect(memory, npages * jffi_getPageSize(), PROT_READ | PROT_EXEC) == 0; #endif } jffi-1.2.7/jni/jffi/MemoryUtil.h000066400000000000000000000030551247047424400164270ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef JFFI_MEMORY_H #define JFFI_MEMORY_H #ifdef __cplusplus extern "C" { #endif int jffi_getPageSize(void); void* jffi_allocatePages(int npages); bool jffi_freePages(void *addr, int npages); bool jffi_makePagesExecutable(void* memory, int npages); #ifdef __cplusplus } #endif #endif jffi-1.2.7/jni/jffi/Struct.c000066400000000000000000000126161247047424400156030ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #if defined(__sun) || defined(_AIX) # include #endif #ifdef _WIN32 # include #endif #include #include #include "com_kenai_jffi_Foreign.h" #include "jffi.h" #include "Exception.h" #ifndef MAX # define MAX(x,y) ((x) > (y) ? (x) : (y)) #endif #define FFI_ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) /* * Class: com_kenai_jffi_Foreign * Method: newStruct * Signature: ([J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newStruct(JNIEnv* env, jobject self, jlongArray typeArray, jboolean isUnion) { ffi_type* s = NULL; int fieldCount; jlong* fieldTypes; int i; if (typeArray == NULL) { throwException(env, NullPointer, "types array cannot be null"); return 0L; } fieldCount = (*env)->GetArrayLength(env, typeArray); if (fieldCount < 1) { throwException(env, IllegalArgument, "No fields specified"); return 0L; } s = calloc(1, sizeof(*s)); if (s == NULL) { throwException(env, OutOfMemory, "failed to allocate memory"); return 0L; } // // Need to terminate the list of field types with a NULL, so allocate 1 extra // s->elements = calloc(fieldCount + 1, sizeof(ffi_type *)); if (s->elements == NULL) { throwException(env, OutOfMemory, "failed to allocate memory"); goto error; } // Copy out all the field descriptors fieldTypes = alloca(fieldCount * sizeof(jlong)); (*env)->GetLongArrayRegion(env, typeArray, 0, fieldCount, fieldTypes); s->type = FFI_TYPE_STRUCT; s->size = 0; s->alignment = 0; for (i = 0; i < fieldCount; ++i) { ffi_type* elem = (ffi_type *) j2p(fieldTypes[i]); if (elem == NULL) { throwException(env, IllegalArgument, "type for field %d is NULL", i); goto error; } if (elem->size == 0) { throwException(env, IllegalArgument, "type for field %d has size 0", i); goto error; } s->elements[i] = elem; if (!isUnion) { s->size = FFI_ALIGN(s->size, elem->alignment) + elem->size; } else { s->size = MAX(s->size, elem->size); } s->alignment = MAX(s->alignment, elem->alignment); } if (s->size == 0) { throwException(env, Runtime, "struct size is zero"); goto error; } // Include tail padding s->size = FFI_ALIGN(s->size, s->alignment); return p2j(s); error: if (s != NULL) { if (s->elements != NULL) { free(s->elements); } free(s); } return 0L; } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newArray(JNIEnv* env, jobject self, jlong type, jint length) { ffi_type* elem = (ffi_type *) j2p(type); ffi_type* s = NULL; int i; if (elem == NULL) { throwException(env, NullPointer, "element type cannot be null"); return 0L; } if (elem->size == 0) { throwException(env, IllegalArgument, "element type size 0"); return 0L; } if (length < 1) { throwException(env, IllegalArgument, "array length == 0"); return 0L; } s = calloc(1, sizeof(*s)); if (s == NULL) { throwException(env, OutOfMemory, "failed to allocate memory"); return 0L; } s->type = FFI_TYPE_STRUCT; s->alignment = elem->alignment; s->size = length * elem->size; // Need to terminate the list of field types with a NULL, so allocate 1 extra s->elements = calloc(length + 1, sizeof(ffi_type *)); if (s->elements == NULL) { throwException(env, OutOfMemory, "failed to allocate memory"); free(s); return 0L; } for (i = 0; i < length; ++i) { s->elements[i] = elem; } return p2j(s); } /* * Class: com_kenai_jffi_Foreign * Method: freeStruct * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeAggregate(JNIEnv* env, jobject self, jlong handle) { ffi_type* s = (ffi_type *) j2p(handle); if (s != NULL) { free(s->elements); free(s); } } jffi-1.2.7/jni/jffi/Type.c000066400000000000000000000076341247047424400152440ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include "com_kenai_jffi_Foreign.h" #include "jffi.h" static ffi_type* typeToFFI(int type) { switch (type) { case com_kenai_jffi_Foreign_TYPE_VOID: return &ffi_type_void; case com_kenai_jffi_Foreign_TYPE_FLOAT:return &ffi_type_float; case com_kenai_jffi_Foreign_TYPE_DOUBLE: return &ffi_type_double; case com_kenai_jffi_Foreign_TYPE_LONGDOUBLE: return &ffi_type_longdouble; case com_kenai_jffi_Foreign_TYPE_UINT8: return &ffi_type_uint8; case com_kenai_jffi_Foreign_TYPE_SINT8: return &ffi_type_sint8; case com_kenai_jffi_Foreign_TYPE_UINT16: return &ffi_type_uint16; case com_kenai_jffi_Foreign_TYPE_SINT16: return &ffi_type_sint16; case com_kenai_jffi_Foreign_TYPE_UINT32: return &ffi_type_uint32; case com_kenai_jffi_Foreign_TYPE_SINT32: return &ffi_type_sint32; case com_kenai_jffi_Foreign_TYPE_UINT64: return &ffi_type_uint64; case com_kenai_jffi_Foreign_TYPE_SINT64: return &ffi_type_sint64; case com_kenai_jffi_Foreign_TYPE_POINTER: return &ffi_type_pointer; case com_kenai_jffi_Foreign_TYPE_UCHAR: return &ffi_type_uchar; case com_kenai_jffi_Foreign_TYPE_SCHAR: return &ffi_type_schar; case com_kenai_jffi_Foreign_TYPE_USHORT: return &ffi_type_ushort; case com_kenai_jffi_Foreign_TYPE_SSHORT: return &ffi_type_sshort; case com_kenai_jffi_Foreign_TYPE_UINT: return &ffi_type_uint; case com_kenai_jffi_Foreign_TYPE_SINT: return &ffi_type_sint; case com_kenai_jffi_Foreign_TYPE_ULONG: return &ffi_type_ulong; case com_kenai_jffi_Foreign_TYPE_SLONG: return &ffi_type_slong; } return NULL; } /* * Class: com_kenai_jffi_Foreign * Method: lookupType * Signature: (I)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_lookupBuiltinType(JNIEnv* env, jobject self, jint type) { return p2j(typeToFFI(type)); } /* * Class: com_kenai_jffi_Foreign * Method: getTypeSize * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getTypeSize(JNIEnv* env, jobject self, jlong handle) { return ((ffi_type *) j2p(handle))->size; } /* * Class: com_kenai_jffi_Foreign * Method: getTypeAlign * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getTypeAlign(JNIEnv* env, jobject self, jlong handle) { return ((ffi_type *) j2p(handle))->alignment; } /* * Class: com_kenai_jffi_Foreign * Method: getTypeType * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getTypeType(JNIEnv* env, jobject self, jlong handle) { return ((ffi_type *) j2p(handle))->type; } jffi-1.2.7/jni/jffi/Type.h000066400000000000000000000025451247047424400152450ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef JFFI_TYPE_H #define JFFI_TYPE_H #include #endif /* JFFI_TYPE_H */ jffi-1.2.7/jni/jffi/darwin-longjmp.S000066400000000000000000000032021247047424400172160ustar00rootroot00000000000000/* libunwind - a platform-independent unwind library Copyright (C) 2004 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef __APPLE__ # define FN(x) _##x #else # define FN(x) x #endif #if defined(__amd64) || defined(__x86_64__) .globl FN(_jffi_longjmp_cont) FN(_jffi_longjmp_cont): push %rax /* push target IP as return address */ mov %rdx, %rax /* set up return-value */ retq #elif defined(__i386__) .globl FN(_jffi_longjmp_cont) FN(_jffi_longjmp_cont): push %eax /* push target IP as return address */ mov %ecx, %eax /* set up return-value */ ret #endif jffi-1.2.7/jni/jffi/darwin-trampoline.S000066400000000000000000000031471247047424400177320ustar00rootroot00000000000000/* libunwind - a platform-independent unwind library Copyright (C) 2004 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef __APPLE__ # define FN(x) _##x #else # define FN(x) x #endif #if defined(__amd64) || defined(__x86_64__) .globl FN(_jffi_fault_trampoline) FN(_jffi_fault_trampoline): and $0xfffffffffffffff0, %rsp push %rdx jmp *%rax #elif defined(__i386__) .globl FN(_jffi_fault_trampoline) FN(_jffi_fault_trampoline): and $0xfffffff0, %esp push %edx /* push target IP as return address */ jmp *%eax #endif jffi-1.2.7/jni/jffi/deprecated.c000066400000000000000000000035001247047424400164070ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #include #include #include #include #include #include #include #include "jffi.h" #include "com_kenai_jffi_Foreign.h" /* * This version of getZeroTerminatedByteArray is deprecated and only here for * binary backwards compatibility. */ JNIEXPORT jbyteArray JNICALL Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArray__JJ(JNIEnv* env, jobject self, jlong address, jlong maxlen) { return Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArray__JI(env, self, address, (jint) maxlen); } jffi-1.2.7/jni/jffi/endian.h000066400000000000000000000041771247047424400155650ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef JFFI_ENDIAN_H #define JFFI_ENDIAN_H #include #include #ifdef __linux__ # include_next #endif #ifdef __sun # include # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # if defined(_BIG_ENDIAN) # define BYTE_ORDER BIG_ENDIAN # elif defined(_LITTLE_ENDIAN) # define BYTE_ORDER LITTLE_ENDIAN # else # error "Cannot determine endian-ness" # endif #endif #if defined(_AIX) && !defined(BYTE_ORDER) # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # if defined(__BIG_ENDIAN__) # define BYTE_ORDER BIG_ENDIAN # elif defined(__LITTLE_ENDIAN__) # define BYTE_ORDER LITTLE_ENDIAN # else # error "Cannot determine endian-ness" # endif #endif #if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) # error "Cannot determine the endian-ness of this platform" #endif #endif /* JFFI_ENDIAN_H */ jffi-1.2.7/jni/jffi/jffi.h000066400000000000000000000141431247047424400152370ustar00rootroot00000000000000/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ #ifndef jffi_jffi_h #define jffi_jffi_h #include #include #include #include #ifndef _WIN32 # include #endif #include "endian.h" #include #include #ifdef __cplusplus extern "C" { #endif #ifndef roundup # define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #endif #ifdef _WIN32 typedef char* caddr_t; #endif #ifdef __GNUC__ # define likely(x) __builtin_expect((x), 1) # define unlikely(x) __builtin_expect((x), 0) #else # define likely(x) (x) # define unlikely(x) (x) #endif /** * Convert a C pointer into a java long */ static inline jlong p2j(void *p) { return (jlong)(uintptr_t) p; } /** * Convert a java long into a C pointer */ static inline void* j2p(jlong j) { return (void *)(uintptr_t) j; } #ifndef __cplusplus static inline jboolean loadClass(JNIEnv* env, const char *name, jclass *classp) { jclass tmp = (*env)->FindClass(env, name); if (tmp == NULL) { return JNI_FALSE; } *classp = (jclass)(*env)->NewGlobalRef(env, tmp); return JNI_TRUE; } #endif typedef union FFIValue { int8_t s8; uint8_t u8; int16_t s16; uint16_t u16; int32_t s32; uint32_t u32; int64_t s64; uint64_t u64; jint i; jlong j; long l; float f; double d; void* p; ffi_sarg sarg; ffi_arg arg; } FFIValue; #ifndef _WIN32 typedef struct ThreadData { int error; int attach_count; JavaVM* attached_vm; struct FaultData_* fault_data; } ThreadData; extern pthread_key_t jffi_threadDataKey; extern ThreadData* jffi_thread_data_init(); static inline ThreadData* thread_data_get() { ThreadData* td = (ThreadData *) pthread_getspecific(jffi_threadDataKey); return likely(td != NULL) ? td : jffi_thread_data_init(); } #endif /* !_WIN32 */ #if BYTE_ORDER == LITTLE_ENDIAN # define return_int(retval) return ((retval).i) # define ARGPTR(argp, type) (argp) #elif BYTE_ORDER == BIG_ENDIAN # define return_int(retval) return ((retval).l & 0xFFFFFFFFL) # define ARGPTR(argp, type) (((caddr_t) (argp)) + sizeof(*argp) - (type)->size) #else # error "Unsupported BYTE_ORDER" #endif # define ffi_call0(ctx, fn, retval) do { \ FFIValue arg0; \ void* ffiValues[] = { &arg0 }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call1(ctx, fn, retval, arg1) do { \ void* ffiValues[] = { ARGPTR(&(arg1), (ctx)->cif.arg_types[0]) }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call2(ctx, fn, retval, arg1, arg2) do {\ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call3(ctx, fn, retval, arg1, arg2, arg3) do { \ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]), \ ARGPTR(&arg3, (ctx)->cif.arg_types[2]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call4(ctx, fn, retval, arg1, arg2, arg3, arg4) do { \ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]), \ ARGPTR(&arg3, (ctx)->cif.arg_types[2]), \ ARGPTR(&arg4, (ctx)->cif.arg_types[3]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call5(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5) do { \ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]), \ ARGPTR(&arg3, (ctx)->cif.arg_types[2]), \ ARGPTR(&arg4, (ctx)->cif.arg_types[3]), \ ARGPTR(&arg5, (ctx)->cif.arg_types[4]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call6(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5, arg6) do { \ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]), \ ARGPTR(&arg3, (ctx)->cif.arg_types[2]), \ ARGPTR(&arg4, (ctx)->cif.arg_types[3]), \ ARGPTR(&arg5, (ctx)->cif.arg_types[4]), \ ARGPTR(&arg6, (ctx)->cif.arg_types[5]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) #if defined(__APPLE__) # define debug(fmt, a...) dprintf(STDERR_FILENO, fmt "\n", ##a) #else # define debug(fmt, a...) do { \ char tmp[1024]; \ write(STDERR_FILENO, tmp, snprintf(tmp, sizeof(tmp), fmt "\n", ##a)); \ } while(0) #endif #ifdef __cplusplus } #endif #endif /* jffi_jffi_h */ jffi-1.2.7/jni/jffi/longjmp.c000066400000000000000000000065651247047424400157730ustar00rootroot00000000000000/* libunwind - a platform-independent unwind library Copyright (C) 2003-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #undef _FORTIFY_SOURCE #include #include #include #include #include #include #include "jffi.h" #include "FaultProtect.h" #if FAULT_PROTECT_ENABLED #include #ifdef __APPLE__ #if defined(__x86_64__) # define SP_OFF 16 #else # define SP_OFF 12 #endif #elif defined __FreeBSD__ # define SP_OFF (sizeof(unw_word_t)) #else # define SP_OFF 0 #endif void jffi_longjmp (jmp_buf env, int val) { extern int _jffi_longjmp_cont; unw_context_t uc; unw_cursor_t c; unw_word_t sp, ip, bp = 0; uintptr_t *wp = (uintptr_t *) env; int i, setjmp_frame; if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0) { debug("failed to get context"); abort (); } #ifdef __x86_86__ # define UNW_REG_BP UNW_X86_64_RBP #else # define UNW_REG_BP UNW_X86_EBP #endif setjmp_frame = 0; do { char name[256]; unw_proc_info_t pi; unw_word_t off; if (unw_get_reg (&c, UNW_REG_BP, &bp) < 0) { abort(); } if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) { abort(); } if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0) { abort(); } unw_get_proc_name(&c, name, sizeof(name), &off); unw_get_proc_info(&c, &pi); // debug("frame %s ip=%llx sp=%llx bp=%llx wp[RP]=%p wp[SP]=%p, pi.start_ip=%llx, pi.end_ip=%llx", // name, (long long) ip, (long long) sp, (long long) bp, (void *) wp[JB_RP], (void *) wp[JB_SP], // pi.start_ip, pi.end_ip); if (wp[JB_SP] > sp || wp[JB_RP] < pi.start_ip || wp[JB_RP] > pi.end_ip) continue; /* found the right frame: */ // debug("found frame to jump back to"); assert (UNW_NUM_EH_REGS >= 2); if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0 || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0 || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) &_jffi_longjmp_cont)) abort (); unw_resume (&c); // should not reach here abort (); } while (unw_step (&c) > 0); // debug("failed to find correct frame to jmp to"); } #endif /* FAULT_PROTECT_ENABLED */ jffi-1.2.7/jni/jffi/queue.h000066400000000000000000000433071247047424400154510ustar00rootroot00000000000000/* $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _JFFI_QUEUE_H_ #define _JFFI_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ #if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) #define _Q_INVALIDATE(a) (a) = ((void *)-1) #else #define _Q_INVALIDATE(a) #endif /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List access methods. */ #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_END(head) NULL #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = SLIST_FIRST(head); \ (var) != SLIST_END(head); \ (var) = SLIST_NEXT(var, field)) #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ for ((varp) = &SLIST_FIRST((head)); \ ((var) = *(varp)) != SLIST_END(head); \ (varp) = &SLIST_NEXT((var), field)) /* * Singly-linked List functions. */ #define SLIST_INIT(head) { \ SLIST_FIRST(head) = SLIST_END(head); \ } #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) #define SLIST_REMOVE_NEXT(head, elm, field) do { \ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->slh_first; \ \ while (curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ _Q_INVALIDATE((elm)->field.sle_next); \ } \ } while (0) /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List access methods */ #define LIST_FIRST(head) ((head)->lh_first) #define LIST_END(head) NULL #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_FOREACH(var, head, field) \ for((var) = LIST_FIRST(head); \ (var)!= LIST_END(head); \ (var) = LIST_NEXT(var, field)) /* * List functions. */ #define LIST_INIT(head) do { \ LIST_FIRST(head) = LIST_END(head); \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) #define LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue access methods. */ #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) #define SIMPLEQ_FOREACH(var, head, field) \ for((var) = SIMPLEQ_FIRST(head); \ (var) != SIMPLEQ_END(head); \ (var) = SIMPLEQ_NEXT(var, field)) /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * tail queue access methods */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) NULL #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) /* XXX */ #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_EMPTY(head) \ (TAILQ_FIRST(head) == TAILQ_END(head)) #define TAILQ_FOREACH(var, head, field) \ for((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head); \ (var) = TAILQ_NEXT(var, field)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for((var) = TAILQ_LAST(head, headname); \ (var) != TAILQ_END(head); \ (var) = TAILQ_PREV(var, headname, field)) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) #define TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ else \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue access methods */ #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_END(head) ((void *)(head)) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) #define CIRCLEQ_EMPTY(head) \ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) #define CIRCLEQ_FOREACH(var, head, field) \ for((var) = CIRCLEQ_FIRST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_NEXT(var, field)) #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ for((var) = CIRCLEQ_LAST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_PREV(var, field)) /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = CIRCLEQ_END(head); \ (head)->cqh_last = CIRCLEQ_END(head); \ } while (0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = CIRCLEQ_END(head); \ if ((head)->cqh_last == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = CIRCLEQ_END(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ CIRCLEQ_END(head)) \ (head).cqh_last = (elm2); \ else \ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ CIRCLEQ_END(head)) \ (head).cqh_first = (elm2); \ else \ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #endif /* !_JFFI_QUEUE_H_ */ jffi-1.2.7/jni/jffi/setjmp.c000066400000000000000000000007051247047424400156150ustar00rootroot00000000000000#include "FaultProtect.h" #if FAULT_PROTECT_ENABLED #include #include #include #include #include #include "jffi.h" #include "Exception.h" int jffi_setjmp(FaultData* f) { void **wp = (void **) f->buf; wp[JB_SP] = __builtin_frame_address (0); wp[JB_RP] = (void *) __builtin_return_address (0); // debug("saved state: sp=%p, rp=%p", wp[JB_SP], wp[JB_RP]); return 0; } #endif jffi-1.2.7/libtest/000077500000000000000000000000001247047424400141155ustar00rootroot00000000000000jffi-1.2.7/libtest/Benchmark.c000066400000000000000000000051771247047424400161650ustar00rootroot00000000000000/* * Copyright (c) 2007 Wayne Meissner. 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 the project 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. */ #include #include void returnVoid() { } void returnVoidI(int arg) { } int returnInt() { return 0; } int returnIntI(int arg) { return arg; } typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; typedef int64_t s64; typedef uint64_t u64; typedef float f32; typedef double f64; typedef void v; typedef char* S; typedef void* P; #define B6(R, T1, T2, T3, T4, T5, T6) R bench_##T1##T2##T3##T4##T5##T6##_##R(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {} #define B5(R, T1, T2, T3, T4, T5) R bench_##T1##T2##T3##T4##T5##_##R(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {} #define B4(R, T1, T2, T3, T4) R bench_##T1##T2##T3##T4##_##R(T1 a1, T2 a2, T3 a3, T4 a4) {} #define B3(R, T1, T2, T3) R bench_##T1##T2##T3##_##R(T1 a1, T2 a2, T3 a3) {} #define B2(R, T1, T2) R bench_##T1##T2##_##R(T1 a1, T2 a2) {} #define B1(R, T1) R bench_##T1##_##R(T1 a1) {} #define BrV(T) B1(v, T); B2(v, T, T); B3(v, T, T, T); B4(v, T, T, T, T); B5(v, T, T, T, T, T); B6(v, T, T, T, T, T, T); BrV(u32); BrV(s32); BrV(s64); BrV(u64); BrV(f32); BrV(f64); BrV(S); BrV(P); jffi-1.2.7/libtest/BufferTest.c000066400000000000000000000042071247047424400163350ustar00rootroot00000000000000/* * Copyright (C) 2007 Wayne Meissner * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project 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. */ #define MEMSET(buf, value, size) do { \ int i; for (i = 0; i < size; ++i) buf[i] = value; \ } while(0) #define MEMCPY(dst, src, size) do { \ int i; for (i = 0; i < size; ++i) dst[i] = src[i]; \ } while(0) #define FILL(JTYPE, CTYPE) \ void fill##JTYPE##Buffer(CTYPE* buf, CTYPE value, int size) { MEMSET(buf, value, size); } #define COPY(JTYPE, CTYPE) \ void copy##JTYPE##Buffer(CTYPE* dst, CTYPE* src, int size) { MEMCPY(dst, src, size); } #define FUNC(JTYPE, CTYPE) \ FILL(JTYPE, CTYPE); \ COPY(JTYPE, CTYPE) FUNC(Byte, char); FUNC(Short, short); FUNC(Int, int); FUNC(Long, long long); FUNC(Float, float); FUNC(Double, double); jffi-1.2.7/libtest/ClosureTest.c000066400000000000000000000125671247047424400165500ustar00rootroot00000000000000/* * Copyright (c) 2007 Wayne Meissner. 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 the project 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. */ #include #ifndef _WIN32 # include #endif void testClosureVrV(void (*closure)(void)) { (*closure)(); } char testClosureVrB(char (*closure)(void)) { return (*closure)(); } short testClosureVrS(short (*closure)(void)) { return (*closure)(); } int testClosureVrI(int (*closure)(void)) { return (*closure)(); } long long testClosureVrL(long long (*closure)(void)) { return (*closure)(); } float testClosureVrF(float (*closure)(void)) { return (*closure)(); } double testClosureVrD(double (*closure)(void)) { return (*closure)(); } void* testClosureVrP(void* (*closure)(void)) { return (*closure)(); } void testClosureBrV(void (*closure)(char), char a1) { (*closure)(a1); } void testClosureSrV(void (*closure)(short), short a1) { (*closure)(a1); } void testClosureIrV(void (*closure)(int), int a1) { (*closure)(a1); } void testClosureLrV(void (*closure)(long long), long long a1) { (*closure)(a1); } void testClosureFrV(void (*closure)(float), float a1) { (*closure)(a1); } void testClosureDrV(void (*closure)(double), double a1) { (*closure)(a1); } void testOptionalClosureBrV(void (*closure)(char), char a1) { if (closure) { (*closure)(a1); } } struct ThreadVrV { void (*closure)(void); int count; }; static void * threadVrV(void *arg) { struct ThreadVrV* t = (struct ThreadVrV *) arg; int i; for (i = 0; i < t->count; i++) { (*t->closure)(); } return NULL; } void testThreadedClosureVrV(void (*closure)(void), int n) { #ifndef _WIN32 pthread_t t; struct ThreadVrV arg; arg.closure = closure; arg.count = n; pthread_create(&t, NULL, threadVrV, &arg); pthread_join(t, NULL); #else int i; for (i = 0; i < t->count; i++) { (*closure)(); } #endif } struct s8f32s32 { char s8; float f32; int s32; }; // Takes a struct argument void testClosureTrV(void (*closure)(struct s8f32s32 s), struct s8f32s32* s) { (*closure)(*s); } // Returns a struct value struct s8f32s32 testClosureVrT(struct s8f32s32 (*closure)()) { return (*closure)(); } typedef int (*returnTypeClosure_t)(int) ; typedef returnTypeClosure_t (*lookupClosure_t)(); int testReturnsClosure(lookupClosure_t lookup, int val) { returnTypeClosure_t func = lookup ? (*lookup)() : NULL; return func ? (*func)(val) : 0; } static int multiplyByTwo(int value) { return value * 2; } returnTypeClosure_t testReturnsFunctionPointer() { return multiplyByTwo; } typedef int (*argumentClosure_t)(int); typedef int (*withArgumentClosure_t)(argumentClosure_t, int); int testArgumentClosure(withArgumentClosure_t closure_with, argumentClosure_t closure_arg, int val) { return (*closure_with)(closure_arg, val); } // // These macros produce functions of the form: // testClosureBIrV(void (*closure)(char, int), char a1, int a2) {} // #define C2_(J1, J2, N1, N2) \ void testClosure##J1##J2##rV(void (*closure)(N1, N2), N1 a1, N2 a2) \ { \ (*closure)(a1, a2); \ } #define C2(J, N) \ C2_(B, J, char, N) \ C2_(S, J, short, N) \ C2_(I, J, int, N) \ C2_(L, J, long long, N) \ C2_(F, J, float, N) \ C2_(D, J, double, N) \ C2(B, char); C2(S, short); C2(I, int); C2(L, long long); C2(F, float); C2(D, double); #define C3_(J1, J2, J3, N1, N2, N3) \ void testClosure##J1##J2##J3##rV(void (*closure)(N1, N2, N3), N1 a1, N2 a2, N3 a3) \ { \ (*closure)(a1, a2, a3); \ } #define C3(J, N) \ C3_(B, J, B, char, N, char) \ C3_(S, J, S, short, N, short) \ C3_(I, J, I, int, N, int) \ C3_(L, J, L, long long, N, long long) \ C3_(F, J, F, float, N, float) \ C3_(D, J, D, double, N, double) \ C3(B, char); C3(S, short); C3(I, int); C3(L, long long); C3(F, float); C3(D, double); C3_(B, S, I, char, short, int); C3_(B, S, L, char, short, long long); C3_(L, S, B, long long, short, char); C3_(L, B, S, long long, char, short); jffi-1.2.7/libtest/EnumTest.c000066400000000000000000000041761247047424400160350ustar00rootroot00000000000000/* * Copyright (c) 2007 Wayne Meissner. 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 the project 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. */ int test_untagged_enum(int val) { return val; } int test_untagged_typedef_enum(int val) { return val; } typedef enum {c1, c2, c3, c4} enum_type1; enum_type1 test_tagged_typedef_enum1(enum_type1 val) { return val; } typedef enum {c5 = 42, c6, c7, c8} enum_type2; enum_type2 test_tagged_typedef_enum2(enum_type2 val) { return val; } typedef enum {c9 = 42, c10, c11 = 4242, c12} enum_type3; enum_type3 test_tagged_typedef_enum3(enum_type3 val) { return val; } typedef enum {c13 = 42, c14 = 4242, c15 = 424242, c16 = 42424242} enum_type4; enum_type4 test_tagged_typedef_enum4(enum_type4 val) { return val; } jffi-1.2.7/libtest/GNUmakefile000066400000000000000000000112711247047424400161710ustar00rootroot00000000000000# -*- makefile -*- BUILD_OS := $(strip $(shell uname -s | tr '[:upper:]' '[:lower:]')) OS ?= $(BUILD_OS) # Default value of $OS on Windows is Windows_NT ifeq ($(OS), Windows_NT) # that's how we detect x64... ifneq ($(findstring 64, $(BUILD_OS)),) OS = win64 else OS = win32 endif endif CPU = $(shell uname -m | sed -e 's/i[345678]86/i386/') MODEL = 32 # Default to 32bit compiles PLATFORM = $(CPU)-$(OS) ifeq ($(OS), sunos) OS = solaris endif ifneq ($(findstring cygwin,$(BUILD_OS)),) # cygwin is always x32 for now OS = win32 endif SRC_DIR = libtest BUILD_DIR ?= build TEST_BUILD_DIR = $(BUILD_DIR)/libtest # Set defaults to unix (linux/solaris/bsd) PREFIX = lib LIBEXT = so LIBNAME = $(PREFIX)test.$(LIBEXT) export MACOSX_DEPLOYMENT_TARGET=10.4 CCACHE := $(strip $(realpath $(shell which ccache 2> /dev/null))) TEST_SRCS = $(wildcard $(SRC_DIR)/*.c) TEST_OBJS := $(patsubst $(SRC_DIR)/%.c, $(TEST_BUILD_DIR)/%.o, $(TEST_SRCS)) # # Compiler/linker flags from: # http://weblogs.java.net/blog/kellyohair/archive/2006/01/compilation_of_1.html JFLAGS = -fno-omit-frame-pointer -fno-strict-aliasing OFLAGS = -O2 $(JFLAGS) WFLAGS = -W -Werror -Wall -Wno-unused -Wno-parentheses PICFLAGS = -fPIC SOFLAGS = -shared -Wl,-O1 LDFLAGS += $(SOFLAGS) IFLAGS = -I"$(BUILD_DIR)" CFLAGS = $(OFLAGS) $(WFLAGS) $(IFLAGS) $(PICFLAGS) -D_REENTRANT ifeq ($(OS), win64) override CPU = x86_64 JDK_INCLUDES=-I$(JNI_DIR)/win32/include -I$(JNI_DIR)/win32/include/win32 CC = x86_64-w64-mingw32-gcc -m64 PICFLAGS = ifneq ($(findstring cygwin, $(BUILD_OS)),) CC += -mno-cygwin LDFLAGS += -mno-cygwin endif CFLAGS += -mwin32 -D_JNI_IMPLEMENTATION_ LDFLAGS += -Wl,--add-stdcall-alias PICFLAGS= SOFLAGS += -shared -static-libgcc PREFIX = LIBEXT = dll endif ifeq ($(OS), win32) CC += -mno-cygwin -mwin32 LDFLAGS += -mno-cygwin -Wl,--add-stdcall-alias PREFIX = PICFLAGS = LIBEXT = dll endif ifeq ($(OS), darwin) ARCHFLAGS = ifneq ($(findstring $(CPU), ppc powerpc),) ARCHES += ppc endif ifneq ($(findstring $(CPU), i386 x86_64),) ARCHES += i386 x86_64 endif ifneq ($(realpath $(wildcard /Xcode3/usr/bin/gcc)),) XCODE=/Xcode3 else XCODE=$(shell xcode-select -print-path) endif ifneq ($(realpath $(wildcard $(XCODE)/usr/bin/gcc-4.0)),) CC = $(XCODE)/usr/bin/gcc-4.0 else CC = $(XCODE)/usr/bin/gcc endif ifneq ($(realpath $(wildcard $(XCODE)/SDKs/MacOSX10.4?.sdk)),) MACSDK = $(XCODE)/SDKs/MacOSX10.4u.sdk ifeq ($(findstring ppc, $(ARCHES)),) ARCHES += ppc endif else MACSDK = $(firstword $(strip $(wildcard $(XCODE)/SDKs/MacOSX10.*.sdk)) $(strip $(wildcard $(XCODE)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.*.sdk))) endif ARCHFLAGS = $(foreach arch, $(ARCHES),-arch $(arch)) CFLAGS += $(ARCHFLAGS) -isysroot $(MACSDK) -DTARGET_RT_MAC_CFM=0 CFLAGS += -fno-common LDFLAGS = $(ARCHFLAGS) -dynamiclib -Wl,-syslibroot,$(MACSDK) -mmacosx-version-min=10.4 LDFLAGS += $(foreach arch, $(ARCHES),-arch $(arch)) # link against the universal libraries on ppc machines LDFLAGS += -L$(MACSDK)/usr/lib LIBEXT = dylib FFI_CFLAGS += -isysroot $(MACSDK) PICFLAGS = SOFLAGS = endif ifeq ($(OS), linux) SOFLAGS += -Wl,-soname,$(LIBNAME) endif ifeq ($(OS), solaris) CC = gcc CFLAGS += -std=c99 LD = /usr/ccs/bin/ld SOFLAGS = -shared -static-libgcc endif ifeq ($(OS), aix) LIBEXT = a SOFLAGS = -shared -static-libgcc PICFLAGS += -pthread endif ifneq ($(findstring bsd, $(OS)),) SOFLAGS = -shared -static-libgcc CFLAGS += -pthread LDFLAGS += -pthread endif ifneq ($(findstring cygwin, $(OS)),) CFLAGS += -mno-cygwin -mwin32 LDFLAGS += -mno-cygwin -Wl,--add-stdcall-alias LIBEXT = dll PREFIX = PICFLAGS = endif ifneq ($(findstring mingw, $(OS)),) LIBEXT = dll PICFLAGS= endif ifeq ($(CPU), sparcv9) MODEL = 64 endif ifeq ($(CPU), amd64) MODEL = 64 endif ifeq ($(CPU), x86_64) MODEL = 64 endif ifeq ($(CPU), s390x) MODEL = 64 endif ifeq ($(CPU), ppc64) MODEL = 64 endif # On platforms (linux, solaris) that support both 32bit and 64bit, force building for one or the other ifneq ($(strip $(findstring $(OS), solaris)),) # Change the CC/LD instead of CFLAGS/LDFLAGS, incase other things in the flags # makes the libffi build choke CC += -m$(MODEL) LD += -m$(MODEL) endif LIBTEST = $(BUILD_DIR)/$(LIBNAME) all: $(LIBTEST) $(TEST_BUILD_DIR)/%.o : $(SRC_DIR)/%.c @mkdir -p $(@D) $(CCACHE) $(CC) $(CFLAGS) -c $< -o $@ $(LIBTEST): $(TEST_OBJS) $(CC) -o $@ $(LDFLAGS) $(TEST_OBJS) -lm clean:: # nothing to do - ant will delete the build dir debug:: @echo OS="$(OS)" @echo BUILD_OS="$(BUILD_OS)" @echo JAVA_HOME="$(JAVA_HOME)" @echo JDK_HOME="$(JDK_HOME)" @echo "SRCS=$(TEST_SRCS)" jffi-1.2.7/libtest/GlobalVariable.c000066400000000000000000000012671247047424400171350ustar00rootroot00000000000000#include #include typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; typedef int64_t s64; typedef uint64_t u64; typedef signed long sL; typedef unsigned long uL; typedef float f32; typedef double f64; #if !defined(__OpenBSD__) typedef unsigned long ulong; #endif typedef void* pointer; typedef void* P; #define GVAR(T) \ extern T gvar_##T; \ T gvar_##T = (T) -1; \ T gvar_##T##_get() { return gvar_##T; }; \ void gvar_##T##_set(T v) { gvar_##T = v; } GVAR(s8); GVAR(u8); GVAR(s16); GVAR(u16); GVAR(s32); GVAR(u32); GVAR(s64); GVAR(u64); GVAR(long); GVAR(ulong); GVAR(pointer); jffi-1.2.7/libtest/LastErrorTest.c000066400000000000000000000033711247047424400170420ustar00rootroot00000000000000/* * Copyright (c) 2008 Wayne Meissner. 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 the project 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. */ #if defined(_WIN32) || defined(__WIN32__) # include #else # include #endif int setLastError(int error) { #if defined(_WIN32) || defined(__WIN32__) SetLastError(error); #else errno = error; #endif return -1; } jffi-1.2.7/libtest/NumberTest.c000066400000000000000000000120531247047424400163520ustar00rootroot00000000000000/* * Copyright (c) 2007 Wayne Meissner. 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 the project 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. */ #include #include #include #include typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; typedef int64_t s64; typedef uint64_t u64; typedef signed long sL; typedef unsigned long uL; typedef float f32; typedef double f64; typedef long double f128; #if !defined(__OpenBSD__) typedef unsigned long ulong; #endif #define ADD(T) T add_##T(T arg1, T arg2) { return arg1 + arg2; } #define SUB(T) T sub_##T(T arg1, T arg2) { return arg1 - arg2; } #define MUL(T) T mul_##T(T arg1, T arg2) { return arg1 * arg2; } #define DIV(T) T div_##T(T arg1, T arg2) { return arg1 / arg2; } #define RET(T) T ret_##T(T arg1) { return arg1; } #define SET(T) static T T##_;void set_##T(T arg1) { T##_ = arg1; } #define GET(T) T get_##T() { return T##_; } typedef char* ptr; #define TEST(T) ADD(T) SUB(T) MUL(T) DIV(T) RET(T) SET(T) GET(T) TEST(s8); TEST(u8); TEST(s16); TEST(u16); TEST(s32); TEST(u32); TEST(s64); TEST(u64); TEST(float); TEST(double); TEST(f128); TEST(long); TEST(ulong); #define ADD2(R, T1, T2) R add_##T1##T2##_##R(T1 arg1, T2 arg2) { return arg1 + arg2; } #define SUB2(R, T1, T2) R sub_##T1##T2##_##R(T1 arg1, T2 arg2) { return arg1 - arg2; } #define MUL2(R, T1, T2) R mul_##T1##T2##_##R(T1 arg1, T2 arg2) { return arg1 * arg2; } #define DIV2(R, T1, T2) R div_##T1##T2##_##R(T1 arg1, T2 arg2) { return arg1 / arg2; } #define T2__(R, T1, T2) ADD2(R, T1, T2) SUB2(R, T1, T2) MUL2(R, T1, T2) DIV2(R, T1, T2) #define T2_(R, T1) \ T2__(R, T1, s8) T2__(R, T1, u8) \ T2__(R, T1, s16) T2__(R, T1, u16) \ T2__(R, T1, s32) T2__(R, T1, u32) \ T2__(R, T1, sL) T2__(R, T1, uL) \ T2__(R, T1, s64) T2__(R, T1, u64) \ #define TEST2(R) \ T2_(R, s8) T2_(R, u8) T2_(R, s16) T2_(R, u16) T2_(R, s32) T2_(R, u32) \ T2_(R, sL) T2_(R, uL) T2_(R, s64) T2_(R, u64) #ifdef notyet TEST2(s32) TEST2(u32) TEST2(s64) TEST2(u64) #endif #define ADD3(R, T1, T2, T3) R add_##T1##T2##T3##_##R(T1 arg1, T2 arg2, T3 arg3) { return arg1 + arg2 + arg3; } #define pack_f32(buf, v) do { *(float *)(buf) = v; } while(0) #define pack_f64(buf, v) do { *(double *)(buf) = v; } while(0) #define pack_f128(buf, v) do { *(long double *)(buf) = v; } while(0) #define pack_int(buf, v) do { *(buf) = v; } while(0) #define pack_s8 pack_int #define pack_u8 pack_int #define pack_s16 pack_int #define pack_u16 pack_int #define pack_s32 pack_int #define pack_u32 pack_int #define pack_s64 pack_int #define pack_u64 pack_int #define pack_sL pack_int #define pack_uL pack_int #define PACK3(R, T1, T2, T3) void pack_##T1##T2##T3##_##R(T1 arg1, T2 arg2, T3 arg3, R* r) { \ pack_##T1(&r[0], arg1); \ pack_##T2(&r[1], arg2); \ pack_##T3(&r[2], arg3); \ } #define T3___(R, T1, T2, T3) PACK3(R, T1, T2, T3) /* SUB2(R, T1, T2) MUL2(R, T1, T2) DIV2(R, T1, T2) */ #define T3__(R, T1, T2) \ T3___(R, T1, T2, s8) T3___(R, T1, T2, u8) \ T3___(R, T1, T2, s16) T3___(R, T1, T2, u16) \ T3___(R, T1, T2, s32) T3___(R, T1, T2, u32) \ T3___(R, T1, T2, sL) T3___(R, T1, T2, uL) \ T3___(R, T1, T2, s64) T3___(R, T1, T2, u64) \ T3___(R, T1, T2, f32) T3___(R, T1, T2, f64) \ #define T3_(R, T1) \ T3__(R, T1, s8) T3__(R, T1, u8) \ T3__(R, T1, s16) T3__(R, T1, u16) \ T3__(R, T1, s32) T3__(R, T1, u32) \ T3__(R, T1, sL) T3__(R, T1, uL) \ T3__(R, T1, s64) T3__(R, T1, u64) \ T3__(R, T1, f32) T3__(R, T1, f64) \ #define TEST3(R) \ T3_(R, s8) T3_(R, u8) T3_(R, s16) T3_(R, u16) T3_(R, s32) T3_(R, u32) \ T3_(R, sL) T3_(R, uL) T3_(R, s64) T3_(R, u64) T3_(R, f32) T3_(R, f64) TEST3(s64) jffi-1.2.7/libtest/PointerTest.c000066400000000000000000000101431247047424400165400ustar00rootroot00000000000000/* * Copyright (c) 2007 Wayne Meissner. 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 the project 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. */ #include #include #include #include #include #include typedef void* ptr; typedef void* pointer; #ifdef _WIN32 typedef char* caddr_t; #endif #define RET(T) T ptr_ret_##T(void* arg1, int offset) { \ T tmp; memcpy(&tmp, (caddr_t) arg1 + offset, sizeof(tmp)); return tmp; \ } #define SET(T) void ptr_set_##T(void* arg1, int offset, T value) { \ memcpy((caddr_t) arg1 + offset, &value, sizeof(value)); \ } #define TEST(T) SET(T) RET(T) TEST(int8_t); TEST(int16_t); TEST(int32_t); TEST(int64_t); TEST(float); TEST(double); TEST(pointer); void* ptr_return_array_element(void **ptrArray, int arrayIndex) { return ptrArray[arrayIndex]; } void ptr_set_array_element(void **ptrArray, int arrayIndex, void *value) { ptrArray[arrayIndex] = value; } void* ptr_malloc(int size) { return calloc(1, size); } void ptr_free(void* ptr) { free(ptr); } void* ptr_from_address(uintptr_t addr) { return (void *) addr; } unsigned long invokeO(unsigned long *ptr) { unsigned long ret = *ptr; *ptr = 0xdeadbeefUL; return ret; } unsigned long invokeON(unsigned long *ptr, unsigned long val) { unsigned long ret = *ptr; *ptr = val; return ret; } unsigned long invokeNO(unsigned long val, unsigned long *ptr) { unsigned long ret = *ptr; *ptr = val; return ret; } unsigned long invokeOO(unsigned long *p1, unsigned long *p2) { unsigned long ret = *p1 + *p2; unsigned long tmp = *p1; *p1 = *p2; *p2 = tmp; return ret; } unsigned long invokeONN(unsigned long *ptr, unsigned long n1, unsigned long n2) { unsigned long ret = *ptr; ptr[0] = n1; ptr[1] = n2; return ret; } unsigned long invokeOON(unsigned long *p1, unsigned long *p2, unsigned long n1) { unsigned long ret = *p1; *p1 = n1; *p2 = n1; return ret; } unsigned long invokeNNO(unsigned long n1, unsigned long n2, unsigned long *ptr) { unsigned long ret = *ptr; ptr[0] = n1; ptr[1] = n2; return ret; } unsigned long invokeNON(unsigned long n1, unsigned long *ptr, unsigned long n2) { unsigned long ret = *ptr; ptr[0] = n1; ptr[1] = n2; return ret; } unsigned long invokeNOO(unsigned long n1, unsigned long *p1, unsigned long *p2) { unsigned long ret = *p1; *p1 = n1; *p2 = n1; return ret; } unsigned long invokeOOO(unsigned long *p1, unsigned long *p2, unsigned long *p3) { unsigned long ret = *p1; *p1 = *p3; *p2 = *p3; *p3 = ret; return ret; } #define N3O1 p1[0] = n1; p1[1] = n2; p1[2] = n3 #define N3O2 p1[0] = n1; p1[1] = n2; p1[2] = n3 jffi-1.2.7/libtest/ReferenceTest.c000066400000000000000000000040771247047424400170270ustar00rootroot00000000000000/* * Copyright (c) 2007 Wayne Meissner. 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 the project 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. */ #include #define REF(T) void ref_##T(T arg, T* result) { *result = arg; } #define ADD(T) void ref_add_##T(T arg1, T arg2, T* result) { *result = arg1 + arg2; } #define SUB(T) void ref_sub_##T(T arg1, T arg2, T* result) { *result = arg1 - arg2; } #define MUL(T) void ref_mul_##T(T arg1, T arg2, T* result) { *result = arg1 * arg2; } #define DIV(T) void ref_div_##T(T arg1, T arg2, T* result) { *result = arg1 / arg2; } #define TEST(T) ADD(T) SUB(T) MUL(T) DIV(T) REF(T) TEST(int8_t); TEST(int16_t); TEST(int32_t); TEST(int64_t); TEST(float); TEST(double); jffi-1.2.7/libtest/StringTest.c000066400000000000000000000034411247047424400163710ustar00rootroot00000000000000/* * Copyright (c) 2007 Wayne Meissner. 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 the project 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. */ #include int string_equals(const char* s1, const char* s2) { return strcmp(s1, s2) == 0; } void string_set(char* s1, const char* s2) { strcpy(s1, s2); } void string_concat(char* dst, const char* src) { strcat(dst, src); } void string_dummy(char* dummy) { } jffi-1.2.7/libtest/StructTest.c000066400000000000000000000107471247047424400164160ustar00rootroot00000000000000/* * Copyright (c) 2007 Wayne Meissner. 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 the project 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. */ #include #include #include #include #include typedef char s8; typedef short s16; typedef int s32; typedef long long s64; typedef float f32; typedef double f64; typedef struct bugged_struct { unsigned char visible; unsigned int x; unsigned int y; short rx; short ry; unsigned char order; unsigned char size; } bugged_struct_t; unsigned int bugged_struct_size() { return sizeof(bugged_struct_t); } struct test1 { char b; short s; int i; long long j; long l; float f; double d; char string[32]; }; struct struct_with_array { char c; int a[5]; }; struct nested { int i; }; struct container { char first; struct nested s; }; int struct_align_nested_struct(struct container* a) { return a->s.i; } void* struct_field_array(struct struct_with_array* s) { return &s->a; } struct container* struct_make_container_struct(int i) { static struct container cs; memset(&cs, 0, sizeof(cs)); cs.first = 1; cs.s.i = i; return &cs; } #define T(x, type) \ type struct_field_##type(struct test1* t) { return t->x; } \ struct type##_align { char first; type value; }; \ type struct_align_##type(struct type##_align* a) { return a->value; } T(b, s8); T(s, s16); T(i, s32); T(j, s64); T(f, f32); T(d, f64); T(l, long); void struct_set_string(struct test1* t, char* s) { strcpy(t->string, s); } struct test1* struct_make_struct(char b, short s, int i, long long ll, float f, double d) { static struct test1 t; memset(&t, 0, sizeof(t)); t.b = b; t.s = s; t.i = i; t.j = ll; t.f = f; t.d = d; return &t; } typedef int (*add_cb)(int a1, int a2); typedef int (*sub_cb)(int a1, int a2); struct test2 { add_cb add_callback; sub_cb sub_callback; }; int struct_call_add_cb(struct test2* t, int a1, int a2) { return t->add_callback(a1, a2); } int struct_call_sub_cb(struct test2* t, int a1, int a2) { return t->sub_callback(a1, a2); } struct struct_with_array* struct_make_struct_with_array(int a_0, int a_1, int a_2, int a_3, int a_4) { static struct struct_with_array s; memset(&s, 0, sizeof(s)); s.a[0] = a_0; s.a[1] = a_1; s.a[2] = a_2; s.a[3] = a_3; s.a[4] = a_4; return &s; } struct s8s32 { char s8; int s32; }; struct s8s32 struct_return_s8s32() { struct s8s32 s; s.s8 = 0x7f; s.s32 = 0x12345678; return s; } struct s8s32 struct_s8s32_set(char s8, int s32) { struct s8s32 s; s.s8 = s8; s.s32 = s32; return s; } int struct_s8s32_get_s8(struct s8s32 s) { return s.s8; } int struct_s8s32_get_s32(struct s8s32 s) { return s.s32; } // Pass a struct and an int arg, ensure the int arg is passed correctly int struct_s8s32_s32_ret_s32(struct s8s32 s, int s32) { return s32; } // Pass a struct and a long long arg, ensure the long long arg is passed correctly long long struct_s8s32_s64_ret_s64(struct s8s32 s, long long s64) { return s64; } jffi-1.2.7/libtest/VariadicTest.c000066400000000000000000000023341247047424400166450ustar00rootroot00000000000000 #include #include #include #include #include typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; typedef int64_t s64; typedef uint64_t u64; typedef signed long sL; typedef unsigned long uL; typedef float F; typedef double D; void pack_varargs(s64* buf, const char* fmt, ...) { va_list ap; int c; double d; va_start(ap, fmt); while ((c = *fmt++)) { switch (c) { case 'c': case 's': case 'i': *buf++ = va_arg(ap, s32); break; case 'l': *buf++ = va_arg(ap, long); break; case 'j': *buf++ = va_arg(ap, s64); break; case 'f': case 'd': d = va_arg(ap, double); memcpy(buf++, &d, sizeof(d)); break; case 'C': case 'S': case 'I': *buf++ = va_arg(ap, u32); break; case 'L': *buf++ = va_arg(ap, unsigned long); break; } } va_end(ap); } jffi-1.2.7/pom.xml000066400000000000000000000146671247047424400140020ustar00rootroot00000000000000 4.0.0 org.sonatype.oss oss-parent 7 com.github.jnr jffi jar 1.2.7 jffi Java Foreign Function Interface http://github.com/jnr/jffi The Apache Software License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo scm:git:git@github.com:jnr/jffi.git scm:git:git@github.com:jnr/jffi.git git@github.com:jnr/jffi.git wmeissner Wayne Meissner wmeissner@gmail.com junit junit 4.8.2 test true true UTF-8 1.6 1.6 make linux-profile linux freebsd-profile freebsd gmake org.apache.maven.plugins maven-release-plugin 2.2 @{project.version} org.apache.maven.plugins maven-antrun-plugin 1.6 build-native-library generate-sources ${project.build.directory}/java run process-test-resources run org.apache.maven.plugins maven-assembly-plugin 2.2 src/main/assembly/native.xml true true native-assemble package single jffi-1.2.7/src/000077500000000000000000000000001247047424400132365ustar00rootroot00000000000000jffi-1.2.7/src/main/000077500000000000000000000000001247047424400141625ustar00rootroot00000000000000jffi-1.2.7/src/main/assembly/000077500000000000000000000000001247047424400160015ustar00rootroot00000000000000jffi-1.2.7/src/main/assembly/native.xml000066400000000000000000000010121247047424400200030ustar00rootroot00000000000000 native jar false ${project.build.directory}/jni /jni **/*.dll **/*.so **/*.jnilib **/*.dylib **/*.a jffi-1.2.7/src/main/java/000077500000000000000000000000001247047424400151035ustar00rootroot00000000000000jffi-1.2.7/src/main/java/com/000077500000000000000000000000001247047424400156615ustar00rootroot00000000000000jffi-1.2.7/src/main/java/com/kenai/000077500000000000000000000000001247047424400167505ustar00rootroot00000000000000jffi-1.2.7/src/main/java/com/kenai/jffi/000077500000000000000000000000001247047424400176665ustar00rootroot00000000000000jffi-1.2.7/src/main/java/com/kenai/jffi/Aggregate.java000066400000000000000000000046741247047424400224320ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.util.logging.Level; import java.util.logging.Logger; public abstract class Aggregate extends Type { private final TypeInfo typeInfo; /** A handle to the foreign interface to keep it alive as long as this object is alive */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final Foreign foreign; Aggregate(Foreign foreign, long handle) { if (handle == 0L) { throw new NullPointerException("Invalid ffi_type handle"); } this.foreign = foreign; this.typeInfo = new TypeInfo(handle, foreign.getTypeType(handle), foreign.getTypeSize(handle), foreign.getTypeAlign(handle)); } final TypeInfo getTypeInfo() { return typeInfo; } public synchronized final void dispose() {} @Override protected void finalize() throws Throwable { try { foreign.freeAggregate(typeInfo.handle); } catch (Throwable t) { Logger.getLogger(getClass().getName()).log(Level.WARNING, "Exception when freeing FFI aggregate: %s", t.getLocalizedMessage()); } finally { super.finalize(); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/Array.java000066400000000000000000000063001247047424400216060ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Describes the layout of a C array */ public final class Array extends Aggregate { /* Keep a strong reference to the element types so it is not GCed */ private final Type elementType; private final int length; /** * Creates a new C array layout description. * * @param elementType The type of each element of the array * @param length The length of the array. */ public static Array newArray(Type elementType, int length) { return new Array(elementType, length); } /** * Creates a new C array layout description. * * @param fields The fields contained in the struct. */ public Array(Type elementType, int length) { super(Foreign.getInstance(), Foreign.getInstance().newArray(elementType.handle(), length)); this.elementType = elementType; this.length = length; } /** * Returns the type of elements in the array * * @return The Type of the elements in the array */ public final Type getElementType() { return elementType; } /** * Returns the number of elements in the array * * @return The number of elements in the array */ public final int length() { return length; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; Array array = (Array) o; if (length != array.length) return false; if (elementType != null ? !elementType.equals(array.elementType) : array.elementType != null) return false; return true; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (elementType != null ? elementType.hashCode() : 0); result = 31 * result + length; return result; } } jffi-1.2.7/src/main/java/com/kenai/jffi/ArrayFlags.java000066400000000000000000000056141247047424400225720ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Flags to use when adding an array as a pointer parameter */ public final class ArrayFlags { /* Stop ArrayFlags from being instantiated */ private ArrayFlags() {} /** Copy the array contents to native memory before calling the function */ public static final int IN = ObjectBuffer.IN; /** After calling the function, reload the array contents from native memory */ public static final int OUT = ObjectBuffer.OUT; /** Pin the array memory and pass the JVM memory pointer directly to the function */ public static final int PINNED = ObjectBuffer.PINNED; /** Append a NUL byte to the array contents after copying to native memory */ public static final int NULTERMINATE = ObjectBuffer.ZERO_TERMINATE; /** For OUT arrays, clear the native memory area before passing to the native function */ public static final int CLEAR = ObjectBuffer.CLEAR; /** * Tests if the flags indicate data should be copied from native memory. * * @param flags The array flags. Any combination of IN | OUT | PINNED | NULTERMINATE. * @return true If array data should be copied from native memory. */ public static final boolean isOut(int flags) { return (flags & (OUT | IN)) != IN; } /** * Tests if the flags indicate data should be copied to native memory. * * @param flags The array flags. Any combination of IN | OUT | PINNED | NULTERMINATE. * @return true If array data should be copied to native memory. */ public static final boolean isIn(int flags) { return (flags & (OUT | IN)) != OUT; } } jffi-1.2.7/src/main/java/com/kenai/jffi/CallContext.java000066400000000000000000000207001247047424400227500ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; /** * Native function call context * * This class holds all the information that JFFI needs to correctly call a * native function, or to implement a callback from native code to java. */ public final class CallContext { /** The native address of the context */ final long contextAddress; /** The number of parameters this function takes */ private final int parameterCount; /** The size of buffer required when packing parameters */ private final int rawParameterSize; /** The return type of this function */ final Type returnType; /** The parameter types of this function */ final Type[] parameterTypes; final long[] parameterTypeHandles; final int flags; /** A handle to the foreign interface to keep it alive as long as this object is alive */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final Foreign foreign = Foreign.getInstance(); /** * Returns a {@link CallContext} instance. This may return a previously cached instance that matches * the signature requested, and should be used in preference to instantiating new instances. * * @param returnType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @param convention The calling convention of the function. * @param saveErrno Indicates that the errno should be saved * @return An instance of CallContext */ public static CallContext getCallContext(Type returnType, Type[] parameterTypes, CallingConvention convention, boolean saveErrno) { return CallContextCache.getInstance().getCallContext(returnType, parameterTypes, convention, saveErrno); } public static CallContext getCallContext(Type returnType, Type[] parameterTypes, CallingConvention convention, boolean saveErrno, boolean faultProtect) { return CallContextCache.getInstance().getCallContext(returnType, parameterTypes, convention, saveErrno, faultProtect); } /** * Creates a new instance of Function with default calling convention. * * @param returnType The return type of the native function. * @param parameterTypes The parameter types the function accepts. */ public CallContext(Type returnType, Type... parameterTypes) { this(returnType, parameterTypes, CallingConvention.DEFAULT, true); } /** * Creates a new instance of Function. * * Function instances created with this constructor will save the * C errno contents after each call. * * @param returnType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @param convention The calling convention of the function. */ public CallContext(Type returnType, Type[] parameterTypes, CallingConvention convention) { this(returnType, parameterTypes, convention, true); } public CallContext(Type returnType, Type[] parameterTypes, CallingConvention convention, boolean saveErrno) { this(returnType, parameterTypes, convention, saveErrno, false); } /** * Creates a new instance of Function. * * @param returnType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @param convention The calling convention of the function. * @param saveErrno Whether the errno should be saved or not */ CallContext(Type returnType, Type[] parameterTypes, CallingConvention convention, boolean saveErrno, boolean faultProtect) { final int flags = (!saveErrno ? Foreign.F_NOERRNO : 0) | (convention == CallingConvention.STDCALL ? Foreign.F_STDCALL : Foreign.F_DEFAULT) | (faultProtect ? Foreign.F_PROTECT : 0); final long h = foreign.newCallContext(returnType.handle(), Type.nativeHandles(parameterTypes), flags); if (h == 0) { throw new RuntimeException("Failed to create native function"); } this.contextAddress = h; // // Keep references to the return and parameter types so they do not get // garbage collected // this.returnType = returnType; this.parameterTypes = parameterTypes.clone(); this.parameterCount = parameterTypes.length; this.rawParameterSize = foreign.getCallContextRawParameterSize(h); this.parameterTypeHandles = Type.nativeHandles(parameterTypes); this.flags = flags; } /** * Gets the number of parameters the native function accepts. * * @return The number of parameters the native function accepts. */ public final int getParameterCount() { return parameterCount; } /** * Gets the number of bytes required to pack all the parameters this function * accepts, into a region of memory. * * @return The number of bytes required to store all paraameters of this function. */ public final int getRawParameterSize() { return rawParameterSize; } /** * Gets the address of the function context. * * @return The address of the native function context struct. */ final long getAddress() { return contextAddress; } /** * Gets the native return type of this function. * * @return The native return type of this function. */ public final Type getReturnType() { return returnType; } /** * Gets the type of a parameter. * * @param index The index of the parameter in the function signature * @return The Type of the parameter. */ public final Type getParameterType(int index) { return parameterTypes[index]; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CallContext that = (CallContext) o; if (flags != that.flags) return false; if (parameterCount != that.parameterCount) return false; if (rawParameterSize != that.rawParameterSize) return false; if (!Arrays.equals(parameterTypes, that.parameterTypes)) return false; if (!returnType.equals(that.returnType)) return false; return true; } @Override public int hashCode() { int result = parameterCount; result = 31 * result + returnType.hashCode(); result = 31 * result + Arrays.hashCode(parameterTypes); result = 31 * result + flags; return result; } @Deprecated public final void dispose() {} @Override protected void finalize() throws Throwable { try { if (contextAddress != 0) { foreign.freeCallContext(contextAddress); } } catch (Throwable t) { Logger.getLogger(getClass().getName()).log(Level.WARNING, "exception when freeing " + getClass() + ": %s", t.getLocalizedMessage()); } finally { super.finalize(); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/CallContextCache.java000066400000000000000000000152451247047424400237040ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class CallContextCache { private final Map contextCache = new ConcurrentHashMap(); private final ReferenceQueue contextReferenceQueue = new ReferenceQueue(); /** Holder class to do lazy allocation of the ClosureManager instance */ private static final class SingletonHolder { static final CallContextCache INSTANCE = new CallContextCache(); } /** * Gets the global instance of the CallContextCache * * @return An instance of a CallContextCache */ public static CallContextCache getInstance() { return SingletonHolder.INSTANCE; } /** Constructs a ClosureManager */ private CallContextCache() { } public final CallContext getCallContext(Type returnType, Type[] parameterTypes, CallingConvention convention) { return getCallContext(returnType, parameterTypes, convention, true, false); } public final CallContext getCallContext(Type returnType, Type[] parameterTypes, CallingConvention convention, boolean saveErrno) { return getCallContext(returnType, parameterTypes, convention, saveErrno, false); } public final CallContext getCallContext(Type returnType, Type[] parameterTypes, CallingConvention convention, boolean saveErrno, boolean faultProtect) { Signature signature = new Signature(returnType, parameterTypes, convention, saveErrno, faultProtect); CallContextRef ref = contextCache.get(signature); CallContext ctx; if (ref != null && (ctx = ref.get()) != null) { return ctx; } // Cull any dead references while ((ref = (CallContextRef) contextReferenceQueue.poll()) != null) { contextCache.remove(ref.signature); } ctx = new CallContext(returnType, parameterTypes.clone(), convention, saveErrno, faultProtect); contextCache.put(signature, new CallContextRef(signature, ctx, contextReferenceQueue)); return ctx; } private static final class CallContextRef extends SoftReference { final Signature signature; public CallContextRef(Signature signature, CallContext ctx, ReferenceQueue queue) { super(ctx, queue); this.signature = signature; } } private static final class Signature { /** * Keep references to the return and parameter types so they do not get * garbage collected until the closure does. */ private final Type returnType; private final Type[] parameterTypes; private final CallingConvention convention; private final boolean saveErrno; private final boolean faultProtect; private int hashCode = 0; public Signature(Type returnType, Type[] parameterTypes, CallingConvention convention, boolean saveErrno, boolean faultProtect) { if (returnType == null || parameterTypes == null) { throw new NullPointerException("null return type or parameter types array"); } this.returnType = returnType; this.parameterTypes = parameterTypes; this.convention = convention; this.saveErrno = saveErrno; this.faultProtect = faultProtect; } @Override public boolean equals(Object obj) { if (obj == null || getClass() != obj.getClass()) { return false; } final Signature other = (Signature) obj; if (convention != other.convention || saveErrno != other.saveErrno || faultProtect != other.faultProtect) { return false; } if (this.returnType != other.returnType && !this.returnType.equals(other.returnType)) { return false; } if (this.parameterTypes.length == other.parameterTypes.length) { for (int i = 0; i < this.parameterTypes.length; ++i) { if (this.parameterTypes[i] != other.parameterTypes[i] && (this.parameterTypes[i] == null || !this.parameterTypes[i].equals(other.parameterTypes[i]))) { return false; } } // All param types are same, return type is same, convention is same, so this is the same signature return true; } return false; } private final int calculateHashCode() { int hash = 7; hash = 53 * hash + (this.returnType != null ? this.returnType.hashCode() : 0); int paramHash = 1; for (int i = 0; i < parameterTypes.length; ++i) { paramHash = 31 * paramHash + parameterTypes[i].hashCode(); } hash = 53 * hash + paramHash; hash = 53 * hash + this.convention.hashCode(); hash = 53 * hash + (this.saveErrno ? 1 : 0); hash = 53 * hash + (this.faultProtect ? 1 : 0); return hash; } @Override public int hashCode() { return hashCode != 0 ? hashCode : (hashCode = calculateHashCode()); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/CallingConvention.java000066400000000000000000000030061247047424400241440ustar00rootroot00000000000000/* * Copyright (C) 2008 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Defines the function calling conventions. */ public enum CallingConvention { /** * The default C calling convention */ DEFAULT, /** * Windows stdcall calling convention */ STDCALL; } jffi-1.2.7/src/main/java/com/kenai/jffi/Closure.java000066400000000000000000000152541247047424400221540ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Represents a native closure. * * A Closure is implemented by java code to act as a C function pointer. */ public interface Closure { public void invoke(Buffer buffer); /** * An interface to the native callback parameter buffer. */ public static interface Buffer { /** * Gets the value of an 8 bit integer parameter. * * @param index The parameter index * @return An 8 bit integer value. */ byte getByte(int index); /** * Gets the value of a 16 bit integer parameter. * * @param index The parameter index * @return A 16 bit integer value. */ short getShort(int index); /** * Gets the value of a 32 bit integer parameter. * * @param index The parameter index * @return A 32 bit integer value. */ int getInt(int index); /** * Gets the value of a 64 bit integer parameter. * * @param index The parameter index * @return A 64 bit integer value. */ long getLong(int index); /** * Gets the value of a 32 bit floating point parameter. * * @param index The parameter index * @return A 32 bit floating point value. */ float getFloat(int index); /** * Gets the value of a 64 bit floating point parameter. * * @param index The parameter index * @return A 64 bit floating point value. */ double getDouble(int index); /** * Gets the value of a native pointer parameter. * * @param index The parameter index * @return A native memory address. */ long getAddress(int index); /** * Gets the address of a struct parameter that is passed by value. * * @param index The parameter index * @return A native memory address. */ long getStruct(int index); /** * Sets the closure return value to an 8 bit integer value. * * @param value The 8 bit integer value to return from the closure. */ void setByteReturn(byte value); /** * Sets the closure return value to a 16 bit integer value. * * @param value The 16 bit integer value to return from the closure. */ void setShortReturn(short value); /** * Sets the closure return value to a 32 bit integer value. * * @param value The 32 bit integer value to return from the closure. */ void setIntReturn(int value); /** * Sets the closure return value to a 64 bit integer value. * * @param value The 64 bit integer value to return from the closure. */ void setLongReturn(long value); /** * Sets the closure return value to a 32 bit floating point value. * * @param value The 32 bit floating point value to return from the closure. */ void setFloatReturn(float value); /** * Sets the closure return value to a 64 bit floating point value. * * @param value The 64 bit floating point value to return from the closure. */ void setDoubleReturn(double value); /** * Sets the closure return value to a native pointer value. * * @param address The native pointer value to return from the closure. */ void setAddressReturn(long address); /** * Sets the closure return value to the contents of a struct * * @param address The address of a native struct to return as a struct value from the closure. */ void setStructReturn(long address); /** * Sets the closure return value to the contents of a struct * * @param data Struct data packed into a byte array to return as a struct value from the closure. * @param offset the offset within the byte array to start copying data */ void setStructReturn(byte[] data, int offset); } /** * A Handle is allocated by the {@link ClosureManager}, as a strong reference * to the native closure trampoline. */ public static interface Handle { /** * Gets the native code address of the closure. * * This can be passed into a native function that takes a function pointer. * * @return The native address of the closure code. */ long getAddress(); /** * Sets whether the closure memory should be released when the Handle is * garbage collected or not. * * @param autorelease If true, the closure memory is automatically managed, * else the closure memory must be explicitly freed. */ void setAutoRelease(boolean autorelease); /** * Releases the closure memory back to the operating system. * * Although the closure trampoline memory will normally be released when * the Handle is garbage collected, this may not happen for some * time, and is non-deterministic. This allows explicit control over * memory reclamation. */ void dispose(); @Deprecated void free(); } } jffi-1.2.7/src/main/java/com/kenai/jffi/ClosureMagazine.java000066400000000000000000000046451247047424400236320ustar00rootroot00000000000000package com.kenai.jffi; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; /** * */ public final class ClosureMagazine { /** A handle to the foreign interface to keep it alive as long as this object is alive */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final Foreign foreign; /** keep a reference to the call context, to avoid GC whilst the magazine is in use */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final CallContext callContext; private final long magazineAddress; private final AtomicBoolean disposed = new AtomicBoolean(false); ClosureMagazine(Foreign foreign, CallContext callContext, long magazineAddress) { this.foreign = foreign; this.callContext = callContext; this.magazineAddress = magazineAddress; } public Closure.Handle allocate(Object proxy) { long closureAddress = foreign.closureMagazineGet(magazineAddress, proxy); return closureAddress != 0L ? new Handle(this, closureAddress, MemoryIO.getInstance().getAddress(closureAddress)) : null; } public void dispose() { if (magazineAddress != 0L && !disposed.getAndSet(true)) { foreign.freeClosureMagazine(magazineAddress); } } private static final class Handle implements Closure.Handle { private final ClosureMagazine magazine; private final long closureAddress, codeAddress; private Handle(ClosureMagazine magazine, long closureAddress, long codeAddress) { this.magazine = magazine; this.closureAddress = closureAddress; this.codeAddress = codeAddress; } public long getAddress() { return codeAddress; } public void setAutoRelease(boolean autorelease) {} public void dispose() { } public void free() {} } @Override protected void finalize() throws Throwable { try { if (magazineAddress != 0L && !disposed.getAndSet(true)) { foreign.freeClosureMagazine(magazineAddress); } } catch (Throwable t) { Logger.getLogger(getClass().getName()).log(Level.WARNING, "exception when freeing " + getClass() + ": %s", t.getLocalizedMessage()); } finally { super.finalize(); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/ClosureManager.java000066400000000000000000000116241247047424400234440ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.reflect.Method; import java.util.Map; import java.util.WeakHashMap; /** * Allocates and manages the lifecycle of native closures (aka callbacks) */ public final class ClosureManager { /** * ClosurePool instances are linked via a SoftReference in the lookup map, so * when all closure instances that that were allocated from the ClosurePool have been * reclaimed, and there is memory pressure, the native closure pool can be freed. * This will allow the CallContext instance to also be collected if it is not * strongly referenced elsewhere, and ejected from the {@link CallContextCache} */ private final Map> poolMap = new WeakHashMap>(); /** Holder class to do lazy allocation of the ClosureManager instance */ private static final class SingletonHolder { static final ClosureManager INSTANCE = new ClosureManager(); } /** * Gets the global instance of the ClosureManager * * @return An instance of a ClosureManager */ public static ClosureManager getInstance() { return SingletonHolder.INSTANCE; } /** Constructs a ClosureManager */ private ClosureManager() { } /** * Wraps a java object that implements the {@link Closure} interface in a * native closure. * * @param closure The java object to be called when the native closure is invoked. * @param returnType The return type of the closure. * @param parameterTypes The parameter types of the closure. * @param convention The calling convention of the closure. * @return A new {@link Closure.Handle} instance. */ public final Closure.Handle newClosure(Closure closure, Type returnType, Type[] parameterTypes, CallingConvention convention) { return newClosure(closure, CallContextCache.getInstance().getCallContext(returnType, parameterTypes, convention)); } /** * Wraps a java object that implements the {@link Closure} interface in a * native closure. * * @param closure The java object to be called when the native closure is invoked. * @param callContext The call context (return type, param types, convention) of the Closure * @return A new {@link Closure.Handle} instance. */ public final Closure.Handle newClosure(Closure closure, CallContext callContext) { ClosurePool pool = getClosurePool(callContext); return pool.newClosureHandle(closure); } public final synchronized ClosurePool getClosurePool(CallContext callContext) { Reference ref = poolMap.get(callContext); ClosurePool pool; if (ref != null && (pool = ref.get()) != null) { return pool; } poolMap.put(callContext, new SoftReference(pool = new ClosurePool(callContext))); return pool; } public ClosureMagazine newClosureMagazine(CallContext callContext, Method method) { Foreign foreign = Foreign.getInstance(); Class[] methodParameterTypes = method.getParameterTypes(); boolean callWithPrimitiveArgs = methodParameterTypes.length < 1 || !Closure.Buffer.class.isAssignableFrom(method.getParameterTypes()[0]); long magazine = foreign.newClosureMagazine(callContext.getAddress(), method, callWithPrimitiveArgs); if (magazine == 0L) { throw new RuntimeException("could not allocate new closure magazine"); } return new ClosureMagazine(foreign, callContext, magazine); } } jffi-1.2.7/src/main/java/com/kenai/jffi/ClosurePool.java000066400000000000000000000250071247047424400230030ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; public final class ClosurePool { private final Set magazines = Collections.synchronizedSet(new HashSet()); private final ConcurrentLinkedQueue freeQueue = new ConcurrentLinkedQueue(); private final ConcurrentLinkedQueue partialQueue = new ConcurrentLinkedQueue(); // // Since the CallContext native handle is used by the native pool code // a strong reference to the call context needs to be kept. // private final CallContext callContext; ClosurePool(CallContext callContext) { this.callContext = callContext; } synchronized void recycle(Magazine magazine) { magazine.recycle(); if (!magazine.isEmpty()) { useMagazine(magazine); } else { // If the magazine was empty during recycling, it means all the closures // allocated from it set autorelease=false, so we cannot re-use it. // Let GC clean it up. magazines.remove(magazine); } } void recycle(Magazine.Slot slot, MagazineHolder holder) { partialQueue.add(new Handle(slot, holder)); } private void useMagazine(Magazine m) { MagazineHolder h = new MagazineHolder(this, m); ArrayList handles = new ArrayList(); Magazine.Slot s; ConcurrentLinkedQueue q = m.isFull() ? freeQueue : partialQueue; while ((s = m.get()) != null) { handles.add(new Handle(s, h)); } q.addAll(handles); } public Closure.Handle newClosureHandle(Closure closure) { Handle h = partialQueue.poll(); if (h == null) { h = freeQueue.poll(); } if (h == null) { h = allocateNewHandle(); } h.slot.proxy.closure = closure; return h; } private Handle allocateNewHandle() { Handle h; while ((h = partialQueue.poll()) == null && (h = freeQueue.poll()) == null) { Magazine m = new Magazine(callContext); useMagazine(m); magazines.add(m); } return h; } /** * Manages the lifecycle of a native closure. * * Implements {@link Closure.Handle} interface. */ private static final class Handle implements Closure.Handle { /** * Keep references to the closure pool so it does not get garbage collected * until all closures using it do. */ final MagazineHolder holder; final Magazine.Slot slot; private volatile boolean disposed; /** * Creates a new Handle to lifecycle manager the native closure. * * @param slot THe magazine slot this handle belongs to * @param holder The magazine holder containing this handle */ Handle(Magazine.Slot slot, MagazineHolder holder) { this.slot = slot; this.holder = holder; } public long getAddress() { if (disposed) { throw new RuntimeException("trying to access disposed closure handle"); } return slot.codeAddress; } public void setAutoRelease(boolean autorelease) { if (!disposed) { slot.autorelease = autorelease; } } @Deprecated public void free() { dispose(); } public synchronized void dispose() { if (!disposed) { disposed = true; slot.autorelease = true; slot.proxy.closure = NULL_CLOSURE; holder.pool.recycle(slot, holder); } } } private static final class Magazine { /** Store a reference to the MemoryIO accessor here for easy access */ private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); /** A handle to the foreign interface to keep it alive as long as this object is alive */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final Foreign foreign = Foreign.getInstance(); private final CallContext ctx; private final long magazine; private final Slot[] slots; private int next; private int freeCount; Magazine(CallContext ctx) { this.ctx = ctx; this.magazine = foreign.newClosureMagazine(ctx.getAddress(), Proxy.METHOD, false); ArrayList slots = new ArrayList(); for (;;) { long h; Proxy proxy = new Proxy(ctx); if ((h = foreign.closureMagazineGet(magazine, proxy)) == 0) { break; } Slot s = new Slot(h, proxy); slots.add(s); } this.slots = new Slot[slots.size()]; slots.toArray(this.slots); next = 0; freeCount = this.slots.length; } Slot get() { while (freeCount > 0 && next < slots.length) { Slot s = slots[next++]; if (s.autorelease) { freeCount--; return s; } } return null; } boolean isFull() { return slots.length == freeCount; } boolean isEmpty() { return freeCount < 1; } void recycle() { for (int i = 0; i < slots.length; i++) { Slot s = slots[i]; if (s.autorelease) { freeCount++; s.proxy.closure = NULL_CLOSURE; } } next = 0; } @Override protected void finalize() throws Throwable { try { boolean release = true; // // If any of the closures allocated from this magazine set autorelease=false // then this magazine cannot be freed, so just let it leak // for (int i = 0; i < slots.length; i++) { if (!slots[i].autorelease) { release = false; break; } } if (magazine != 0 && release) { foreign.freeClosureMagazine(magazine); } } finally { super.finalize(); } } static final class Slot { /** * The address of the native closure structure. * * Note: This is NOT the code address, but a pointer to the structure * which contains the code address. */ final long handle; /** The code trampoline address */ final long codeAddress; final Proxy proxy; volatile boolean autorelease; public Slot(long handle, Proxy proxy) { this.handle = handle; this.proxy = proxy; this.autorelease = true; codeAddress = IO.getAddress(handle); } } } private static final class MagazineHolder { final ClosurePool pool; final Magazine magazine; public MagazineHolder(ClosurePool pool, Magazine magazine) { this.pool = pool; this.magazine = magazine; } @Override protected void finalize() throws Throwable { try { pool.recycle(magazine); } finally { super.finalize(); } } } /** * This is a proxy passed to the native code, to be called by the * native trampoline code. */ static final class Proxy { static final Method METHOD = getMethod(); /** * Keep references to the return and parameter types so they do not get * garbage collected until the closure does. */ final CallContext callContext; volatile Closure closure; /** * Gets the Method to be invoked by native code * * @return The method to be invoked by native code */ private static Method getMethod() { try { return Proxy.class.getDeclaredMethod("invoke", new Class[]{long.class, long.class}); } catch (Throwable ex) { throw new RuntimeException(ex); } } Proxy(CallContext callContext) { this.closure = NULL_CLOSURE; this.callContext = callContext; } /** * Invoked by the native closure trampoline to execute the java side of * the closure. * * @param retvalAddress The address of the native return value buffer * @param paramAddress The address of the native parameter buffer. */ public void invoke(long retvalAddress, long paramAddress) { closure.invoke(new DirectClosureBuffer(callContext, retvalAddress, paramAddress)); } } private static final Closure NULL_CLOSURE = new Closure() { public void invoke(Buffer buffer) { } }; } jffi-1.2.7/src/main/java/com/kenai/jffi/DirectClosureBuffer.java000066400000000000000000000133221247047424400244330ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Implementation of the {@link Closure.Buffer} interface to read/write * parameter and return value data in native memory */ final class DirectClosureBuffer implements Closure.Buffer { private static final MemoryIO IO = MemoryIO.getInstance(); private static final NativeWordIO WordIO = NativeWordIO.getInstance(); private static final long PARAM_SIZE = Platform.getPlatform().addressSize() / 8; private final long retval; private final long parameters; /* Keep references to the return and parameter types to prevent garbage collection */ private final CallContext callContext; public DirectClosureBuffer(CallContext callContext, long retval, long parameters) { super(); this.callContext = callContext; this.retval = retval; this.parameters = parameters; } public final byte getByte(int index) { return IO.getByte(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final short getShort(int index) { return IO.getShort(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final int getInt(int index) { return IO.getInt(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final long getLong(int index) { return IO.getLong(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final float getFloat(int index) { return IO.getFloat(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final double getDouble(int index) { return IO.getDouble(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final long getAddress(int index) { return IO.getAddress(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final long getStruct(int index) { return IO.getAddress(parameters + (index * PARAM_SIZE)); } public final void setByteReturn(byte value) { WordIO.put(retval, value); } public final void setShortReturn(short value) { WordIO.put(retval, value); } public final void setIntReturn(int value) { WordIO.put(retval, value); } public final void setLongReturn(long value) { IO.putLong(retval, value); } public final void setFloatReturn(float value) { IO.putFloat(retval, value); } public final void setDoubleReturn(double value) { IO.putDouble(retval, value); } public final void setAddressReturn(long address) { IO.putAddress(retval, address); } public void setStructReturn(long value) { IO.copyMemory(value, retval, callContext.getReturnType().size()); } public void setStructReturn(byte[] data, int offset) { IO.putByteArray(retval, data, offset, callContext.getReturnType().size()); } /** * Reads annd writes data types that are smaller than the size of a native * long, as a native long for compatibility with FFI. */ private static abstract class NativeWordIO { public static final NativeWordIO getInstance() { return Platform.getPlatform().addressSize() == 32 ? NativeWordIO32.INSTANCE : NativeWordIO64.INSTANCE; } /** * Writes a native long argument to native memory. * * @param address The address to write the value at * @param value The value to write. */ abstract void put(long address, int value); /** * Reads a native long argument from native memory. * @param address The memory address to read the value from * @return An integer */ abstract int get(long address); } private static final class NativeWordIO32 extends NativeWordIO { private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); static final NativeWordIO INSTANCE = new NativeWordIO32(); void put(long address, int value) { IO.putInt(address, value); } int get(long address) { return IO.getInt(address); } } private static final class NativeWordIO64 extends NativeWordIO { private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); static final NativeWordIO INSTANCE = new NativeWordIO64(); void put(long address, int value) { IO.putLong(address, value); } int get(long address) { return (int) IO.getLong(address); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/DirectObjectParameterStrategy.java000066400000000000000000000041701247047424400264600ustar00rootroot00000000000000/* * Copyright (C) 2011 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * */ abstract public class DirectObjectParameterStrategy extends ObjectParameterStrategy { public DirectObjectParameterStrategy(boolean isDirect, ObjectParameterType parameterType) { super(isDirect, parameterType); } abstract public long getAddress(Object parameter); public final Object object(Object parameter) { throw new RuntimeException("direct object " + (parameter != null ? parameter.getClass() : "null") + " has no array"); } public final int offset(Object parameter) { throw new RuntimeException("direct object " + (parameter != null ? parameter.getClass() : "null") + "has no offset"); } public final int length(Object parameter) { throw new RuntimeException("direct object " + (parameter != null ? parameter.getClass() : "null") + "has no length"); } } jffi-1.2.7/src/main/java/com/kenai/jffi/FaultException.java000066400000000000000000000021621247047424400234640ustar00rootroot00000000000000package com.kenai.jffi; public final class FaultException extends RuntimeException { private final int signal; FaultException(int signal, long[] ip, long[] procname, long[] libname) { super(String.format("Received signal %d", signal)); setStackTrace(createStackTrace(ip, procname, libname, fillInStackTrace().getStackTrace())); this.signal = signal; } private static StackTraceElement[] createStackTrace(long[] ip, long[] procname, long[] libname, StackTraceElement[] existingTrace) { java.util.List trace = new java.util.ArrayList(); for (int i = 0; i < ip.length; i++) { String procName = new String(Foreign.getZeroTerminatedByteArray(procname[i])); String libName = new String(Foreign.getZeroTerminatedByteArray(libname[i])); trace.add(new StackTraceElement("native", procName, libName, -1)); } trace.addAll(java.util.Arrays.asList(existingTrace)); return trace.toArray(new StackTraceElement[trace.size()]); } public int getSignal() { return signal; } } jffi-1.2.7/src/main/java/com/kenai/jffi/Foreign.java000066400000000000000000002154311247047424400221300ustar00rootroot00000000000000/* * Copyright (C) 2007, 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ /** * Interface to the foreign function interface. */ package com.kenai.jffi; import java.lang.reflect.Method; import java.nio.Buffer; import java.nio.ByteBuffer; final class Foreign { private static abstract class InstanceHolder { static final InstanceHolder INSTANCE = getInstanceHolder(); private static InstanceHolder getInstanceHolder() { try { Init.load(); Foreign foreign = new Foreign(); if ((foreign.getVersion() & 0xffff00) != (VERSION_MAJOR << 16 | VERSION_MINOR << 8)) { String msg = String.format("incorrect native library version %d.%d, expected %d.%d", (foreign.getVersion() >> 16 & 0xff), (foreign.getVersion() >> 8 & 0xff), VERSION_MAJOR, VERSION_MINOR); return new InValidInstanceHolder(new UnsatisfiedLinkError(msg)); } foreign.init(); return new ValidInstanceHolder(foreign); } catch (Throwable throwable) { return new InValidInstanceHolder(throwable); } } abstract Foreign getForeign(); } private static UnsatisfiedLinkError newLoadError(Throwable cause) { UnsatisfiedLinkError error = new UnsatisfiedLinkError(); error.initCause(cause); return error; } private static final class ValidInstanceHolder extends InstanceHolder { final Foreign foreign; public ValidInstanceHolder(Foreign foreign) { this.foreign = foreign; } final Foreign getForeign() { return foreign; } } private static final class InValidInstanceHolder extends InstanceHolder { private final Throwable cause; public InValidInstanceHolder(Throwable cause) { this.cause = cause; } final Foreign getForeign() { throw newLoadError(cause); } } public static Foreign getInstance() { return InstanceHolder.INSTANCE.getForeign(); } private Foreign() { } private static int getVersionField(String name) { try { Class c = Class.forName(Foreign.class.getPackage().getName() + ".Version"); return (Integer) c.getField(name).get(c); } catch (Throwable t) { throw new RuntimeException(t); } } public final static int VERSION_MAJOR = getVersionField("MAJOR"); public final static int VERSION_MINOR = getVersionField("MINOR"); public final static int VERSION_MICRO = getVersionField("MICRO"); public final static int TYPE_VOID = 0; public final static int TYPE_FLOAT = 2; public final static int TYPE_DOUBLE = 3; public final static int TYPE_LONGDOUBLE = 4; public final static int TYPE_UINT8 = 5; public final static int TYPE_SINT8 = 6; public final static int TYPE_UINT16 = 7; public final static int TYPE_SINT16 = 8; public final static int TYPE_UINT32 = 9; public final static int TYPE_SINT32 = 10; public final static int TYPE_UINT64 = 11; public final static int TYPE_SINT64 = 12; public final static int TYPE_STRUCT = 13; public final static int TYPE_POINTER = 14; public final static int TYPE_UCHAR = 101; public final static int TYPE_SCHAR = 102; public final static int TYPE_USHORT = 103; public final static int TYPE_SSHORT = 104; public final static int TYPE_UINT = 105; public final static int TYPE_SINT = 106; public final static int TYPE_ULONG = 107; public final static int TYPE_SLONG = 108; /** Perform lazy binding. Only resolve symbols as needed */ public static final int RTLD_LAZY = 0x00001; /** Resolve all symbols when loading the library */ public static final int RTLD_NOW = 0x00002; /** Symbols in this library are not made available to other libraries */ public static final int RTLD_LOCAL = 0x00004; /** All symbols in the library are made available to other libraries */ public static final int RTLD_GLOBAL = 0x00008; /** Pages can be read */ public static final int PROT_READ = 0x1; /** Pages can be written */ public static final int PROT_WRITE = 0x2; /** Pages can be executed */ public static final int PROT_EXEC = 0x4; /** Pages cannot be accessed */ public static final int PROT_NONE = 0x0; /** Share changes */ public static final int MAP_SHARED = 0x1; public static final int MAP_PRIVATE = 0x2; /** Use the specified address */ public static final int MAP_FIXED = 0x10; public static final int MAP_NORESERVE = 0x40; public static final int MAP_ANON = 0x100; public static final int MAP_ALIGN = 0x200; /** Code segment memory */ public static final int MAP_TEXT = 0x400; /** Win32 VirtualAlloc/VirtualProtect flags */ public static final int PAGE_NOACCESS = 0x0001; public static final int PAGE_READONLY = 0x0002; public static final int PAGE_READWRITE = 0x0004; public static final int PAGE_WRITECOPY = 0x0008; public static final int PAGE_EXECUTE = 0x0010; public static final int PAGE_EXECUTE_READ = 0x0020; public static final int PAGE_EXECUTE_READWRITE = 0x0040; public static final int PAGE_EXECUTE_WRITECOPY = 0x0080; public static final int MEM_COMMIT = 0x1000; public static final int MEM_RESERVE = 0x2000; public static final int MEM_DECOMMIT = 0x4000; public static final int MEM_RELEASE = 0x8000; public static final int MEM_FREE = 0x10000; public static final int MEM_PRIVATE = 0x20000; public static final int MEM_MAPPED = 0x40000; public static final int MEM_RESET = 0x80000; public static final int MEM_TOP_DOWN = 0x100000; public static final int MEM_PHYSICAL = 0x400000; public static final int MEM_4MB_PAGES = 0x80000000; /* * possible return values for JNI functions. */ public static final int JNI_OK = 0; /* success */ public static final int JNI_ERR = (-1); /* unknown error */ public static final int JNI_EDETACHED = (-2); /* thread detached from the VM */ public static final int JNI_EVERSION = (-3); /* JNI version error */ public static final int JNI_ENOMEM = (-4); /* not enough memory */ public static final int JNI_EEXIST = (-5); /* VM already created */ public static final int JNI_EINVAL = (-6); /* invalid arguments */ /* * Function flags */ /** * Default calling convention */ public static final int F_DEFAULT = 0x0; /** * Windows STDCALL calling convention */ public static final int F_STDCALL = 0x1; /** * Do not save errno after each call */ public static final int F_NOERRNO = 0x2; /** * Try to capture segmentation faults and convert to java exceptions */ public static final int F_PROTECT = 0x4; /** * Gets the native stub library version. * * @return The version in the form of (VERSION_MAJOR << 16 | VERSION_MINOR << 8 | VERSION_MICRO) */ final native int getVersion(); /** * Initializes any native method/field/class ids */ private native void init(); private static native boolean isFaultProtectionEnabled(); static boolean isMemoryProtectionEnabled() { try { return isFaultProtectionEnabled(); } catch (UnsatisfiedLinkError e) { return false; } } /** * Opens a dynamic library. * * This is a very thin wrapper around the native dlopen(3) call. * * @param name The name of the dynamic library to open. Pass null to get a * handle to the current process. * @param flags The flags to dlopen. A bit mask of {@link #RTLD_LAZY}, {@link #RTLD_NOW}, * {@link #RTLD_LOCAL}, {@link #RTLD_GLOBAL} * @return A native handle to the dynamic library. */ static native long dlopen(String name, int flags); /** * Closes a dynamic library opened by {@link #dlopen}. * * @param handle The dynamic library handle returned by {@link #dlopen} */ static native void dlclose(long handle); /** * Locates the memory address of a dynamic library symbol. * * @param handle A dynamic library handle obtained from {@link #dlopen} * @param name The name of the symbol. * @return The address where the symbol in loaded in memory. */ static native long dlsym(long handle, String name); /** * Gets the last error raised by {@link #dlopen} or {@link #dlsym} * * @return The error string. */ static native String dlerror(); /** * Allocates native memory. * * @param size The number of bytes of memory to allocate * @param clear Whether the memory should be cleared (each byte set to zero). * @return The native address of the allocated memory. */ static native long allocateMemory(long size, boolean clear); /** * Releases memory allocated via {@link #allocateMemory} back to the system. * * @param address The address of the memory to release. */ static native void freeMemory(long address); /** * Gets the size of a page of memory. * * @return The size of a memory page in bytes. */ static native long pageSize(); /** * Calls the Unix mmap(2) function * * This method is undefined on windows. * * @param addr The desired address to map the memory at, or 0 for random address. * @param len The length of the memory region. * @param prot The protection mode for the memory region. * @param flags * @param fd * @param off * @return The address of the mapping on success, -1 on error. */ static native long mmap(long addr, long len, int prot, int flags, int fd, long off); /** * Calls the Unix munmap(2) function. * * @param addr The address to unmap. * @param len The size of the region. * @return 0 on success, -1 on error. */ static native int munmap(long addr, long len); /** * Calls the Unix mprotect(2) function. * @param addr The address to unmap. * @param len The size of the region. * @param prot The new protection mode. * @return 0 on success, -1 on error. */ static native int mprotect(long addr, long len, int prot); static native long VirtualAlloc(long addr, int size, int flags, int prot); static native boolean VirtualFree(long addr, int size, int flags); static native boolean VirtualProtect(long addr, int size, int prot); /** * Creates a new native call context. * * @param returnType The return type of the function * @param paramTypes The types of the parameters * @param flags A bitmask of F_DEFAULT, F_STDCALL, F_NOERRNO, F_PROTECT * * @return The native address of a new function context */ final native long newCallContext(long returnType, long[] paramTypes, int flags); /** * Frees a call context created by {@link #newCallContext} * * @param callContext The native call context to free */ final native void freeCallContext(long callContext); /** * Gets the size required to pack parameters for the function in libffi raw format. * * @param callContext The call context * @return The size in bytes required to pack parameters in raw format */ final native int getCallContextRawParameterSize(long callContext); final native boolean isRawParameterPackingEnabled(); /** * Gets the last error returned by a native function * * @return An integer. */ static native int getLastError(); /** * Sets the native errno value * * @param error The value to set errno to. */ static native void setLastError(int error); final native long newClosureMagazine(long contextAddress, Method closureMethod, boolean callWithPrimitiveParameters); final native void freeClosureMagazine(long closurePool); final native long closureMagazineGet(long closurePool, Object proxy); /** * Gets the address of the ffi_type structure for the builtin type * * @param type The FFI type enum value * @return The address of the ffi_type struct for this type, or null */ final native long lookupBuiltinType(int type); /** * Gets the native size of the type * * @param handle Address of the type structure * @return The native size of the type */ final native int getTypeSize(long handle); /** * Gets the minimum required alignment of the FFI type * * @param handle Address of the type structure * @return The minimum required alignment */ final native int getTypeAlign(long handle); /** * Gets the primitive type enum for the FFI type * * @param handle Address of the type structure * @return The builtin primitive type of the type structure */ final native int getTypeType(long handle); /** * Allocates a new FFI struct or union layout * * @param fields An array of ffi_type pointers describing the fields of the struct * @param isUnion If true, then fields are all positioned at offset=0, else * fields are sequentially positioned. * @return The native address of the ffi_type structure for the new struct layout * @see #freeAggregate(long) */ final native long newStruct(long[] fields, boolean isUnion); /** * Allocates a new FFI array type. * * @param elementType the type of each element in the array. * @param length the number of elements in the array. * @return The native address of the ffi_type structure for the new array layout. * @see #freeAggregate(long) */ final native long newArray(long elementType, int length); /** * Frees a FFI struct, union or array handle allocated via {@link #newStruct} or {@link #newArray}. * * @param handle The FFI struct handle */ final native void freeAggregate(long handle); /** * Invokes a function with no arguments, and returns a 32 bit integer. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @return A 32 bit integer value. */ static native int invokeI0(long callContext, long function); /** * Invokes a function with no arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @return A 32 bit integer value. */ static native int invokeI0NoErrno(long callContext, long function); /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI1(long callContext, long function, int arg1); /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * This method does not save the errno value. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI1NoErrno(long callContext, long function, int arg1); /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI2(long callContext, long function, int arg1, int arg2); /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI2NoErrno(long callContext, long function, int arg1, int arg2); /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI3(long callContext, long function, int arg1, int arg2, int arg3); /** * Invokes a function with four integer arguments, and returns a 32 bit integer. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The third 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI4(long callContext, long function, int arg1, int arg2, int arg3, int arg4); /** * Invokes a function with five integer arguments, and returns a 32 bit integer. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @param arg5 The fifth 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI5(long callContext, long function, int arg1, int arg2, int arg3, int arg4, int arg5); /** * Invokes a function with six integer arguments, and returns a 32 bit integer. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @param arg5 The fifth 32 bit integer argument. * @param arg6 The sixth 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI6(long callContext, long function, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ static native int invokeI3NoErrno(long callContext, long function, int arg1, int arg2, int arg3); static native int invokeI4NoErrno(long callContext, long function, int arg1, int arg2, int arg3, int arg4); static native int invokeI5NoErrno(long callContext, long function, int arg1, int arg2, int arg3, int arg4, int arg5); static native int invokeI6NoErrno(long callContext, long function, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); /** * Invokes a function with no arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newCallContext}. * @return A 64 bit integer value. */ static native long invokeL0(long ctx, long function); /** * Invokes a function with one 64 bit integer argument, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The 64 bit integer argument. * @return A 64 bit integer value. */ static native long invokeL1(long ctx, long function, long arg1); /** * Invokes a function with two 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @return A 64 bit integer value. */ static native long invokeL2(long ctx, long function, long arg1, long arg2); /** * Invokes a function with three 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @return A 64 bit integer value. */ static native long invokeL3(long ctx, long function, long arg1, long arg2, long arg3); /** * Invokes a function with four 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @return A 64 bit integer value. */ static native long invokeL4(long ctx, long function, long arg1, long arg2, long arg3, long arg4); /** * Invokes a function with five 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @return A 64 bit integer value. */ static native long invokeL5(long ctx, long function, long arg1, long arg2, long arg3, long arg4, long arg5); /** * Invokes a function with six 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @param arg6 The sixth 64 bit integer argument. * @return A 64 bit integer value. */ static native long invokeL6(long ctx, long function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); static native long invokeL0NoErrno(long ctx, long function); static native long invokeL1NoErrno(long ctx, long function, long arg1); static native long invokeL2NoErrno(long ctx, long function, long arg1, long arg2); static native long invokeL3NoErrno(long ctx, long function, long arg1, long arg2, long arg3); static native long invokeL4NoErrno(long ctx, long function, long arg1, long arg2, long arg3, long arg4); static native long invokeL5NoErrno(long ctx, long function, long arg1, long arg2, long arg3, long arg4, long arg5); static native long invokeL6NoErrno(long ctx, long function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); /** * Invokes a function with zero numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newCallContext}. * @return A numeric value. */ static native long invokeN0(long ctx, long function); /** * Invokes a function with one numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first numeric argument. * @return A numeric value. */ static native long invokeN1(long ctx, long function, long arg1); /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @return A numeric value. */ static native long invokeN2(long ctx, long function, long arg1, long arg2); /** * Invokes a function with three numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @return A numeric value. */ static native long invokeN3(long ctx, long function, long arg1, long arg2, long arg3); /** * Invokes a function with four numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @return A numeric value. */ static native long invokeN4(long ctx, long function, long arg1, long arg2, long arg3, long arg4); /** * Invokes a function with five numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @return A numeric value. */ static native long invokeN5(long ctx, long function, long arg1, long arg2, long arg3, long arg4, long arg5); /** * Invokes a function with six numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newCallContext}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @param arg6 The sixth numeric argument. * @return A numeric value. */ static native long invokeN6(long ctx, long function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); /** * Invokes a function with one numeric argument, and returns a numeric value. * * @param callContext The FFI call context describing the function to invoke. * @param functionAddress The native function to invoke. * @param n1 The first numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1flags Object flags (direction, type, idx). * @param o1off The offset from the start of the array or buffer. * @param o1len The length of the array to use. */ static native long invokeN1O1(long callContext, long functionAddress, long n1, Object o1, int o1flags, int o1off, int o1len); /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param callContext The FFI call context describing the function to invoke. * @param functionAddress The native function to invoke. * @param n1 The first numeric argument. * @param n2 The second numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1flags Object flags (direction, type, idx). * @param o1off The offset from the start of the array or buffer. * @param o1len The length of the array to use. * @return A numeric value. */ static native long invokeN2O1(long callContext, long functionAddress, long n1, long n2, Object o1, int o1flags, int o1off, int o1len); /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param callContext The FFI call context describing the function to invoke. * @param functionAddress The native function to invoke. * @param n1 The first numeric argument. * @param n2 The second numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1off The offset from the start of the array or buffer. * @param o1len The length of the array to use. * @param o1flags Object flags (direction, type, idx). * @param o2 An Object (array or buffer), to be passed as a pointer. * @param o2off The offset from the start of the array or buffer. * @param o2len The length of the array to use. * @param o2flags Object flags (direction, type, idx). * @return A numeric value. */ static native long invokeN2O2(long callContext, long functionAddress, long n1, long n2, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len); /** * Invokes a function with three numeric arguments, and returns a numeric value. * * @param callContext The FFI call context describing the function to invoke. * @param functionAddress The native function to invoke. * @param n1 The first numeric argument. * @param n2 The second numeric argument. * @param n3 The third numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1off The offset from the start of the array or buffer. * @param o1len The length of the array to use. * @param o1flags Object flags (direction, type, parameter index). * @return A numeric value. */ static native long invokeN3O1(long callContext, long functionAddress, long n1, long n2, long n3, Object o1, int o1flags, int o1off, int o1len); static native long invokeN3O2(long callContext, long functionAddress, long n1, long n2, long n3, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len); static native long invokeN3O3(long callContext, long functionAddress, long n1, long n2, long n3, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len); static native long invokeN4O1(long callContext, long functionAddress, long n1, long n2, long n3, long n4, Object o1, int o1flags, int o1off, int o1len); static native long invokeN4O2(long callContext, long functionAddress, long n1, long n2, long n3, long n4, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len); static native long invokeN4O3(long callContext, long functionAddress, long n1, long n2, long n3, long n4, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len); static native long invokeN4O4(long callContext, long functionAddress, long n1, long n2, long n3, long n4, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len, Object o4, int o4flags, int o4off, int o4len); static native long invokeN5O1(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, Object o1, int o1flags, int o1off, int o1len); static native long invokeN5O2(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len); static native long invokeN5O3(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len); static native long invokeN5O4(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len, Object o4, int o4flags, int o4off, int o4len); static native long invokeN5O5(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len, Object o4, int o4flags, int o4off, int o4len, Object o5, int o5flags, int o5off, int o5len); static native long invokeN6O1(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1flags, int o1off, int o1len); static native long invokeN6O2(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len); static native long invokeN6O3(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len); static native long invokeN6O4(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len, Object o4, int o4flags, int o4off, int o4len); static native long invokeN6O5(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len, Object o4, int o4flags, int o4off, int o4len, Object o5, int o5flags, int o5off, int o5len); static native long invokeN6O6(long callContext, long functionAddress, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1flags, int o1off, int o1len, Object o2, int o2flags, int o2off, int o2len, Object o3, int o3flags, int o3off, int o3len, Object o4, int o4flags, int o4off, int o4len, Object o5, int o5flags, int o5off, int o5len, Object o6, int o6flags, int o6off, int o6len); /** * Invokes a function that returns a 32 bit integer. * @param callContext The address of the call context structure from {@link #newCallContext}. * @param buffer A byte array containing the arguments to the function. * @return A 32 bit integer value. */ static native int invokeArrayReturnInt(long callContext, long function, byte[] buffer); /** * Invokes a function that returns a 64 bit integer. * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param buffer A byte array containing the arguments to the function. * @return A 64 bit integer value. */ static native long invokeArrayReturnLong(long callContext, long function, byte[] buffer); /** * Invokes a function that returns a 32 bit floating point value. * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param buffer A byte array containing the arguments to the function. * @return A 32 bit floating point value. */ static native float invokeArrayReturnFloat(long callContext, long function, byte[] buffer); /** * Invokes a function that returns a 64 bit floating point value. * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param buffer A byte array containing the arguments to the function. * @return A 64 bit floating point value. */ static native double invokeArrayReturnDouble(long callContext, long function, byte[] buffer); /** * Invokes a function and pack the return value into a byte array. * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param paramBuffer A byte array containing the arguments to the function. */ static native void invokeArrayReturnStruct(long callContext, long function, byte[] paramBuffer, byte[] returnBuffer, int offset); /** * Invokes a function that returns a java object. * * This is only useful when calling JNI functions directly. * * @param callContext The address of the call context structure from {@link #newCallContext}. * @param function The address of the function to invoke. * @param paramBuffer A byte array containing the arguments to the function. */ static native Object invokeArrayWithObjectsReturnObject(long callContext, long function, byte[] paramBuffer, int objectCount, int[] objectInfo, Object[] objects); /* ---------------------------------------------------------------------- */ static native int invokeArrayWithObjectsInt32(long callContext, long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects); static native long invokeArrayWithObjectsInt64(long callContext, long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects); static native float invokeArrayWithObjectsFloat(long callContext, long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects); static native double invokeArrayWithObjectsDouble(long callContext, long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects); static native void invokeArrayWithObjectsReturnStruct(long callContext, long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects, byte[] returnBuffer, int returnBufferOffset); /* ---------------------------------------------------------------------- */ static native int invokeArrayO1Int32(long callContext, long function, byte[] buffer, Object o1, int o1Info, int o1off, int o1len); static native int invokeArrayO2Int32(long callContext, long function, byte[] buffer, Object o1, int o1Info, int o1off, int o1len, Object o2, int o2info, int o2off, int o2len); static native long invokeArrayO1Int64(long callContext, long function, byte[] buffer, Object o1, int o1Info, int o1off, int o1len); static native long invokeArrayO2Int64(long callContext, long function, byte[] buffer, Object o1, int o1Info, int o1off, int o1len, Object o2, int o2info, int o2off, int o2len); /* ---------------------------------------------------------------------- */ /** * Invokes a function, with the parameters loaded into native memory buffers, * and the function result is stored in a native memory buffer. * * @param functionContext The address of the function context structure from {@link #newCallContext}. * @param returnBuffer The address of the native buffer to place the result * of the function call in. * @param parameters An array of addresses of the function parameters. */ static native void invokePointerParameterArray(long callContext, long functionContext, long returnBuffer, long[] parameters); /** * Reads an 8 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A byte containing the value. */ static native byte getByte(long address); /** * Reads a 16 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A short containing the value. */ static native short getShort(long address); /** * Reads a 32 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return An int containing the value. */ static native int getInt(long address); /** * Reads a 64 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ static native long getLong(long address); /** * Reads a 32 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A float containing the value. */ static native float getFloat(long address); /** * Reads a 64 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A double containing the value. */ static native double getDouble(long address); /** * Reads a native memory address from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ static native long getAddress(long address); /** * Writes an 8 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putByte(long address, byte value); /** * Writes a 16 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putShort(long address, short value); /** * Writes a 32 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putInt(long address, int value); /** * Writes a 64 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putLong(long address, long value); /** * Writes a 32 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putFloat(long address, float value); /** * Writes a 64 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putDouble(long address, double value); /** * Writes a native memory address value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putAddress(long address, long value); /** * Sets a region of native memory to a specific byte value. * * @param address The address of start of the native memory. * @param size The number of bytes to set. * @param value The value to set the native memory to. */ static native void setMemory(long address, long size, byte value); /** * Copies contents of a native memory location to another native memory location. * * @param src The source memory address. * @param dst The destination memory address. * @param size The number of bytes to copy. */ static native void copyMemory(long src, long dst, long size); /** * Writes a java byte array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putByteArray(long address, byte[] data, int offset, int length); /** * Reads a java byte array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getByteArray(long address, byte[] data, int offset, int length); /** * Writes a java char array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putCharArray(long address, char[] data, int offset, int length); /** * Reads a java char array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getCharArray(long address, char[] data, int offset, int length); /** * Writes a java short array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putShortArray(long address, short[] data, int offset, int length); /** * Reads a java short array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getShortArray(long address, short[] data, int offset, int length); /** * Writes a java int array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putIntArray(long address, int[] data, int offset, int length); /** * Reads a java int array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getIntArray(long address, int[] data, int offset, int length); /** * Writes a java long array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putLongArray(long address, long[] data, int offset, int length); /** * Reads a java long array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getLongArray(long address, long[] data, int offset, int length); /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putFloatArray(long address, float[] data, int offset, int length); /** * Reads a java float array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getFloatArray(long address, float[] data, int offset, int length); /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putDoubleArray(long address, double[] data, int offset, int length); /** * Reads a java double array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getDoubleArray(long address, double[] data, int offset, int length); /** * Gets the address of a byte value in a native memory region. * * @param address The native memory address to start searching. * @param value The value to search for. * @param len The size of the native memory region being searched. * @return The address of the value, or 0 (zero) if not found. */ static native long memchr(long address, int value, long len); /** * Copies potentially overlapping memory areas. * * @param dst The destination memory address. * @param src The source memory address. * @param len The number of bytes to copy. */ static native void memmove(long dst, long src, long len); /** * Copies non-overlapping memory areas. * * @param dst The destination memory address. * @param src The source memory address. * @param len The number of bytes to copy. */ static native void memcpy(long dst, long src, long len); /** * Gets the length of a native ascii or utf-8 string. * * @param address The native address of the string. * @return The length of the string, in bytes. */ static native long strlen(long address); /** * Copies a zero (nul) terminated by array from native memory. * * This method will search for a zero byte, starting from address * and stop once a zero byte is encountered. The returned byte array does not * contain the terminating zero byte. * * @param address The address to copy the array from * @return A byte array containing the bytes copied from native memory. */ static native byte[] getZeroTerminatedByteArray(long address); /** * Copies a zero (nul) terminated by array from native memory. * * This method will search for a zero byte, starting from address * and stop once a zero byte is encountered. The returned byte array does not * contain the terminating zero byte. * * @param address The address to copy the array from * @param maxlen The maximum number of bytes to search for the nul terminator * @return A byte array containing the bytes copied from native memory. */ static native byte[] getZeroTerminatedByteArray(long address, int maxlen); /** * Copies a java byte array to native memory and appends a NUL terminating byte. * * Note A total of length + 1 bytes is written to native memory. * * @param address The address to copy to. * @param data The byte array to copy to native memory * @param offset The offset within the byte array to begin copying from * @param length The number of bytes to copy to native memory */ static native void putZeroTerminatedByteArray(long address, byte[] data, int offset, int length); /** * Reads an 8 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A byte containing the value. */ static native byte getByteChecked(long address); /** * Reads a 16 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A short containing the value. */ static native short getShortChecked(long address); /** * Reads a 32 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return An int containing the value. */ static native int getIntChecked(long address); /** * Reads a 64 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ static native long getLongChecked(long address); /** * Reads a 32 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A float containing the value. */ static native float getFloatChecked(long address); /** * Reads a 64 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A double containing the value. */ static native double getDoubleChecked(long address); /** * Reads a native memory address from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ static native long getAddressChecked(long address); /** * Writes an 8 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putByteChecked(long address, byte value); /** * Writes a 16 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putShortChecked(long address, short value); /** * Writes a 32 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putIntChecked(long address, int value); /** * Writes a 64 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putLongChecked(long address, long value); /** * Writes a 32 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putFloatChecked(long address, float value); /** * Writes a 64 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putDoubleChecked(long address, double value); /** * Writes a native memory address value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ static native void putAddressChecked(long address, long value); /** * Sets a region of native memory to a specific byte value. * * @param address The address of start of the native memory. * @param size The number of bytes to set. * @param value The value to set the native memory to. */ static native void setMemoryChecked(long address, long size, byte value); /** * Copies contents of a native memory location to another native memory location. * * @param src The source memory address. * @param dst The destination memory address. * @param size The number of bytes to copy. */ static native void copyMemoryChecked(long src, long dst, long size); /** * Writes a java byte array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putByteArrayChecked(long address, byte[] data, int offset, int length); /** * Reads a java byte array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getByteArrayChecked(long address, byte[] data, int offset, int length); /** * Writes a java char array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putCharArrayChecked(long address, char[] data, int offset, int length); /** * Reads a java char array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getCharArrayChecked(long address, char[] data, int offset, int length); /** * Writes a java short array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putShortArrayChecked(long address, short[] data, int offset, int length); /** * Reads a java short array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getShortArrayChecked(long address, short[] data, int offset, int length); /** * Writes a java int array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putIntArrayChecked(long address, int[] data, int offset, int length); /** * Reads a java int array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getIntArrayChecked(long address, int[] data, int offset, int length); /** * Writes a java long array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putLongArrayChecked(long address, long[] data, int offset, int length); /** * Reads a java long array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getLongArrayChecked(long address, long[] data, int offset, int length); /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putFloatArrayChecked(long address, float[] data, int offset, int length); /** * Reads a java float array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getFloatArrayChecked(long address, float[] data, int offset, int length); /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ static native void putDoubleArrayChecked(long address, double[] data, int offset, int length); /** * Reads a java double array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ static native void getDoubleArrayChecked(long address, double[] data, int offset, int length); /** * Gets the address of a byte value in a native memory region. * * @param address The native memory address to start searching. * @param value The value to search for. * @param len The size of the native memory region being searched. * @return The address of the value, or 0 (zero) if not found. */ static native long memchrChecked(long address, int value, long len); /** * Copies potentially overlapping memory areas. * * @param dst The destination memory address. * @param src The source memory address. * @param len The number of bytes to copy. */ static native void memmoveChecked(long dst, long src, long len); /** * Copies non-overlapping memory areas. * * @param dst The destination memory address. * @param src The source memory address. * @param len The number of bytes to copy. */ static native void memcpyChecked(long dst, long src, long len); /** * Gets the length of a native ascii or utf-8 string. * * @param address The native address of the string. * @return The length of the string, in bytes. */ static native long strlenChecked(long address); /** * Copies a zero Checked(nul) terminated by array from native memory. * * This method will search for a zero byte, starting from address * and stop once a zero byte is encountered. The returned byte array does not * contain the terminating zero byte. * * @param address The address to copy the array from * @return A byte array containing the bytes copied from native memory. */ static native byte[] getZeroTerminatedByteArrayChecked(long address); /** * Copies a zero Checked(nul) terminated by array from native memory. * * This method will search for a zero byte, starting from address * and stop once a zero byte is encountered. The returned byte array does not * contain the terminating zero byte. * * @param address The address to copy the array from * @param maxlen The maximum number of bytes to search for the nul terminator * @return A byte array containing the bytes copied from native memory. */ static native byte[] getZeroTerminatedByteArrayChecked(long address, int maxlen); /** * Copies a java byte array to native memory and appends a NUL terminating byte. * * Note A total of length + 1 bytes is written to native memory. * * @param address The address to copy to. * @param data The byte array to copy to native memory * @param offset The offset within the byte array to begin copying from * @param length The number of bytes to copy to native memory */ static native void putZeroTerminatedByteArrayChecked(long address, byte[] data, int offset, int length); /** * Creates a new Direct ByteBuffer for a native memory region. * * @param address The start of the native memory region. * @param capacity The size of the native memory region. * @return A ByteBuffer representing the native memory region. */ final native ByteBuffer newDirectByteBuffer(long address, int capacity); /** * Gets the native memory address of a direct ByteBuffer * * @param buffer A direct ByteBuffer to get the address of. * @return The native memory address of the buffer contents, or null if not a direct buffer. */ final native long getDirectBufferAddress(Buffer buffer); final native void longDoubleFromDouble(double doubleValue, byte[] buf, int off, int len); final native double longDoubleToDouble(byte[] buf, int off, int len); final native void longDoubleFromString(String doubleString, byte[] buf, int off, int len); final native String longDoubleToString(byte[] buf, int off, int len); final native String longDoubleToEngineeringString(byte[] buf, int off, int len); final native String longDoubleToPlainString(byte[] buf, int off, int len); final native long newNativeMethod(String name, String signature, long functionContext); final native void freeNativeMethod(long handle); final native long compileNativeMethods(long[] methods); final native void freeCompiledMethods(long handle); /** * * @param clazz The java class to register the native methods on * @param handle The handle returned from compileNativeMethods * @return true if successful */ final native boolean registerNativeMethods(Class clazz, long handle); final native void unregisterNativeMethods(Class clazz); final native long getSaveErrnoFunction(); final native void setCallContextErrorFunction(long ctx, long fn); final native long getSaveErrnoCtxFunction(); final native int getJNIVersion(); final native long getJavaVM(); final native void fatalError(String msg); final native Class defineClass(String name, Object loader, byte[] buf, int off, int len); final native Class defineClass(String name, Object loader, ByteBuffer buf); final native Object allocObject(Class clazz); final native int registerNatives(Class clazz, long methods, int methodCount); final native int unregisterNatives(Class clazz); final native String getArch(); } jffi-1.2.7/src/main/java/com/kenai/jffi/Function.java000066400000000000000000000126261247047424400223250ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Native function invocation context * * This class holds all the information that JFFI needs to correctly call a * native function. */ public final class Function { private final CallContext callContext; /** The address of the function */ final long functionAddress; final long contextAddress; /** * Creates a new instance of Function with default calling convention. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param paramTypes The parameter types the function accepts. */ public Function(long address, Type returnType, Type... paramTypes) { this(address, returnType, paramTypes, CallingConvention.DEFAULT, true); } /** * Creates a new instance of Function with default calling convention. * * @param address The native address of the function to invoke. */ public Function(long address, CallContext callContext) { this.functionAddress = address; this.callContext = callContext; this.contextAddress = callContext.getAddress(); } /** * Creates a new instance of Function. * * Function instances created with this constructor will save the * C errno contents after each call. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param paramTypes The parameter types the function accepts. * @param convention The calling convention of the function. */ public Function(long address, Type returnType, Type[] paramTypes, CallingConvention convention) { this(address, returnType, paramTypes, convention, true); } /** * Creates a new instance of Function. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param paramTypes The parameter types the function accepts. * @param convention The calling convention of the function. * @param saveErrno Whether the errno should be saved or not */ public Function(long address, Type returnType, Type[] paramTypes, CallingConvention convention, boolean saveErrno) { this.functionAddress = address; this.callContext = CallContext.getCallContext(returnType, paramTypes, convention, saveErrno); this.contextAddress = callContext.getAddress(); } /** * Gets the number of parameters the native function accepts. * * @return The number of parameters the native function accepts. */ public final int getParameterCount() { return callContext.getParameterCount(); } /** * Gets the number of bytes required to pack all the parameters this function * accepts, into a region of memory. * * @return The number of bytes required to store all paraameters of this function. */ public final int getRawParameterSize() { return callContext.getRawParameterSize(); } public final CallContext getCallContext() { return callContext; } /** * Gets the address of the function context. * * @return The address of the native function context struct. */ final long getContextAddress() { return contextAddress; } /** * Gets the address of the function. * * @return The address of the native function. */ public final long getFunctionAddress() { return functionAddress; } /** * Gets the native return type of this function. * * @return The native return type of this function. */ public final Type getReturnType() { return callContext.getReturnType(); } /** * Gets the type of a parameter. * * @param index The index of the parameter in the function signature * @return The Type of the parameter. */ public final Type getParameterType(int index) { return callContext.getParameterType(index); } @Deprecated public final void dispose() {} } jffi-1.2.7/src/main/java/com/kenai/jffi/HeapInvocationBuffer.java000066400000000000000000000530541247047424400246010ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.math.BigDecimal; import java.nio.ByteOrder; /** * An implementation of {@link InvocationBuffer} that packs its parameters onto * a java heap allocated buffer. */ public final class HeapInvocationBuffer extends InvocationBuffer { private static final int PARAM_SIZE = 8; private final CallContext callContext; private final byte[] buffer; private ObjectBuffer objectBuffer; private int paramOffset = 0; private int paramIndex = 0; /** * Creates a new instance of HeapInvocationBuffer. * * @param function The function that this buffer is going to be used with. */ public HeapInvocationBuffer(Function function) { this.callContext = function.getCallContext(); buffer = new byte[Encoder.getInstance().getBufferSize(callContext)]; } /** * Creates a new instance of HeapInvocationBuffer. * * @param callContext The {@link CallContext} describing how the function should be invoked */ public HeapInvocationBuffer(CallContext callContext) { this.callContext = callContext; buffer = new byte[Encoder.getInstance().getBufferSize(callContext)]; } /** * Creates a new instance of HeapInvocationBuffer. * * @param context The {@link CallContext} describing how the function should be invoked */ public HeapInvocationBuffer(CallContext context, int objectCount) { this.callContext = context; buffer = new byte[Encoder.getInstance().getBufferSize(context)]; objectBuffer = new ObjectBuffer(objectCount); } /** * Gets the backing array of this InvocationBuffer * * @return The backing array for this buffer. */ byte[] array() { return buffer; } /** * Gets the object buffer used to store java heap array parameters * * @return An ObjectBuffer */ ObjectBuffer objectBuffer() { return objectBuffer; } public final void putByte(final int value) { paramOffset = Encoder.getInstance().putByte(buffer, paramOffset, value); ++paramIndex; } public final void putShort(final int value) { paramOffset = Encoder.getInstance().putShort(buffer, paramOffset, value); ++paramIndex; } public final void putInt(final int value) { paramOffset = Encoder.getInstance().putInt(buffer, paramOffset, value); ++paramIndex; } public final void putLong(final long value) { paramOffset = Encoder.getInstance().putLong(buffer, paramOffset, value); ++paramIndex; } public final void putFloat(final float value) { paramOffset = Encoder.getInstance().putFloat(buffer, paramOffset, value); ++paramIndex; } public final void putDouble(final double value) { paramOffset = Encoder.getInstance().putDouble(buffer, paramOffset, value); ++paramIndex; } public final void putLongDouble(final double value) { byte[] ld = new byte[Type.LONGDOUBLE.size()]; Foreign.getInstance().longDoubleFromDouble(value, ld, 0, Type.LONGDOUBLE.size()); getObjectBuffer().putArray(paramIndex, ld, 0, ld.length, ObjectBuffer.IN); paramOffset += PARAM_SIZE; ++paramIndex; } public final void putLongDouble(final BigDecimal value) { byte[] ld = new byte[Type.LONGDOUBLE.size()]; Foreign.getInstance().longDoubleFromString(value.toEngineeringString(), ld, 0, Type.LONGDOUBLE.size()); getObjectBuffer().putArray(paramIndex, ld, 0, ld.length, ObjectBuffer.IN); paramOffset += PARAM_SIZE; ++paramIndex; } public final void putAddress(final long value) { paramOffset = Encoder.getInstance().putAddress(buffer, paramOffset, value); ++paramIndex; } private final ObjectBuffer getObjectBuffer() { if (objectBuffer == null) { objectBuffer = new ObjectBuffer(); } return objectBuffer; } public final void putArray(final byte[] array, int offset, int length, int flags) { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final short[] array, int offset, int length, int flags) { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final int[] array, int offset, int length, int flags) { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final long[] array, int offset, int length, int flags) { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final float[] array, int offset, int length, int flags) { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final double[] array, int offset, int length, int flags) { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putDirectBuffer(final java.nio.Buffer value, int offset, int length) { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putDirectBuffer(paramIndex++, value, offset, length); } public final void putStruct(final byte[] struct, int offset) { final Type type = callContext.getParameterType(paramIndex); paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putArray(paramIndex, struct, offset, type.size(), ObjectBuffer.IN); ++paramIndex; } public final void putStruct(final long struct) { final Type type = callContext.getParameterType(paramIndex); paramOffset = Encoder.getInstance().putAddress(buffer, paramOffset, struct); ++paramIndex; } public final void putObject(Object o, ObjectParameterStrategy strategy, ObjectParameterInfo info) { if (strategy.isDirect()) { paramOffset = Encoder.getInstance().putAddress(buffer, paramOffset, strategy.address(o)); } else { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putObject(strategy.object(o), strategy.offset(o), strategy.length(o), ObjectBuffer.makeObjectFlags(info.ioflags(), strategy.typeInfo, paramIndex)); } ++paramIndex; } public final void putObject(Object o, ObjectParameterStrategy strategy, int flags) { if (strategy.isDirect()) { paramOffset = Encoder.getInstance().putAddress(buffer, paramOffset, strategy.address(o)); } else { paramOffset = Encoder.getInstance().skipAddress(paramOffset); getObjectBuffer().putObject(strategy.object(o), strategy.offset(o), strategy.length(o), ObjectBuffer.makeObjectFlags(flags, strategy.typeInfo, paramIndex)); } ++paramIndex; } public final void putJNIEnvironment() { paramOffset = Encoder.getInstance().putAddress(buffer, paramOffset, 0L); getObjectBuffer().putJNI(paramIndex++, null, ObjectBuffer.JNIENV); } public final void putJNIObject(Object obj) { paramOffset = Encoder.getInstance().putAddress(buffer, paramOffset, 0L); getObjectBuffer().putJNI(paramIndex++, obj, ObjectBuffer.JNIOBJECT); } /** * Encodes java data types into native parameter frames */ static abstract class Encoder { private static class SingletonHolder { static final Encoder INSTANCE = new DefaultEncoder(ArrayIO.getInstance()); } static Encoder getInstance() { return SingletonHolder.INSTANCE; } /** Gets the size in bytes of the buffer required for the function */ public abstract int getBufferSize(CallContext callContext); /** * Encodes a byte value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putByte(byte[] buffer, int offset, int value); /** * Encodes a short value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putShort(byte[] buffer, int offset, int value); /** * Encodes an int value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putInt(byte[] buffer, int offset, int value); /** * Encodes a long value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putLong(byte[] buffer, int offset, long value); /** * Encodes a float value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putFloat(byte[] buffer, int offset, float value); /** * Encodes a double value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putDouble(byte[] buffer, int offset, double value); /** * Encodes a native memory address value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putAddress(byte[] buffer, int offset, long value); public abstract int skipAddress(int offset); } private static final class DefaultEncoder extends Encoder { private final ArrayIO io; public DefaultEncoder(ArrayIO io) { this.io = io; } public final int getBufferSize(CallContext callContext) { return callContext.getParameterCount() * PARAM_SIZE; } public final int putByte(byte[] buffer, int offset, int value) { io.putByte(buffer, offset, value); return offset + PARAM_SIZE; } public final int putShort(byte[] buffer, int offset, int value) { io.putShort(buffer, offset, value); return offset + PARAM_SIZE; } public final int putInt(byte[] buffer, int offset, int value) { io.putInt(buffer, offset, value); return offset + PARAM_SIZE; } public final int putLong(byte[] buffer, int offset, long value) { io.putLong(buffer, offset, value); return offset + PARAM_SIZE; } public final int putFloat(byte[] buffer, int offset, float value) { io.putFloat(buffer, offset, value); return offset + PARAM_SIZE; } public final int putDouble(byte[] buffer, int offset, double value) { io.putDouble(buffer, offset, value); return offset + PARAM_SIZE; } public final int putAddress(byte[] buffer, int offset, long value) { io.putAddress(buffer, offset, value); return offset + PARAM_SIZE; } @Override public int skipAddress(int offset) { return offset + PARAM_SIZE; } } private static abstract class ArrayIO { private static final class SingletonHolder { private static final ArrayIO DEFAULT; static { ArrayIO io; try { switch (Platform.getPlatform().addressSize()) { case 32: io = ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN) ? ArrayIO.getBE32IO() : ArrayIO.getLE32IO(); break; case 64: io = ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN) ? ArrayIO.getBE64IO() : ArrayIO.getLE64IO(); break; default: throw new IllegalArgumentException("unsupported address size: " + Platform.getPlatform().addressSize()); } } catch (Throwable error) { io = newInvalidArrayIO(error); } DEFAULT = io; } } static ArrayIO getInstance() { return SingletonHolder.DEFAULT; } static ArrayIO getBE32IO() { return BE32ArrayIO.INSTANCE; } static ArrayIO getLE32IO() { return LE32ArrayIO.INSTANCE; } static ArrayIO getLE64IO() { return LE64ArrayIO.INSTANCE; } static ArrayIO getBE64IO() { return BE64ArrayIO.INSTANCE; } static ArrayIO newInvalidArrayIO(Throwable error) { return new InvalidArrayIO(error); } public abstract void putByte(byte[] buffer, int offset, int value); public abstract void putShort(byte[] buffer, int offset, int value); public abstract void putInt(byte[] buffer, int offset, int value); public abstract void putLong(byte[] buffer, int offset, long value); public final void putFloat(byte[] buffer, int offset, float value) { putInt(buffer, offset, Float.floatToRawIntBits(value)); } public final void putDouble(byte[] buffer, int offset, double value) { putLong(buffer, offset, Double.doubleToRawLongBits(value)); } public abstract void putAddress(byte[] buffer, int offset, long value); } /** * Base class for all little-endian architecture array encoders. */ private static abstract class LittleEndianArrayIO extends ArrayIO { public final void putByte(byte[] buffer, int offset, int value) { buffer[offset] = (byte) value; } public final void putShort(byte[] buffer, int offset, int value) { buffer[offset] = (byte) value; buffer[offset + 1] = (byte) (value >> 8); } public final void putInt(byte[] buffer, int offset, int value) { buffer[offset] = (byte) value; buffer[offset + 1] = (byte) (value >> 8); buffer[offset + 2] = (byte) (value >> 16); buffer[offset + 3] = (byte) (value >> 24); } public final void putLong(byte[] buffer, int offset, long value) { buffer[offset] = (byte) value; buffer[offset + 1] = (byte) (value >> 8); buffer[offset + 2] = (byte) (value >> 16); buffer[offset + 3] = (byte) (value >> 24); buffer[offset + 4] = (byte) (value >> 32); buffer[offset + 5] = (byte) (value >> 40); buffer[offset + 6] = (byte) (value >> 48); buffer[offset + 7] = (byte) (value >> 56); } } /** * Little endian, 32 bit implementation of ArrayIO */ private static final class LE32ArrayIO extends LittleEndianArrayIO { static final ArrayIO INSTANCE = new LE32ArrayIO(); public final void putAddress(byte[] buffer, int offset, long value) { buffer[offset] = (byte) value; buffer[offset + 1] = (byte) (value >> 8); buffer[offset + 2] = (byte) (value >> 16); buffer[offset + 3] = (byte) (value >> 24); } } /** * Little endian, 64 bit implementation of ArrayIO */ private static final class LE64ArrayIO extends LittleEndianArrayIO { static final ArrayIO INSTANCE = new LE64ArrayIO(); public final void putAddress(byte[] buffer, int offset, long value) { putLong(buffer, offset, value); } } /** * Base class for all big-endian architecture array encoders. */ private static abstract class BigEndianArrayIO extends ArrayIO { public final void putByte(byte[] buffer, int offset, int value) { buffer[offset] = (byte) value; } public final void putShort(byte[] buffer, int offset, int value) { buffer[offset + 0] = (byte) (value >> 8); buffer[offset + 1] = (byte) value; } public final void putInt(byte[] buffer, int offset, int value) { buffer[offset + 0] = (byte) (value >> 24); buffer[offset + 1] = (byte) (value >> 16); buffer[offset + 2] = (byte) (value >> 8); buffer[offset + 3] = (byte) value; } public final void putLong(byte[] buffer, int offset, long value) { buffer[offset + 0] = (byte) (value >> 56); buffer[offset + 1] = (byte) (value >> 48); buffer[offset + 2] = (byte) (value >> 40); buffer[offset + 3] = (byte) (value >> 32); buffer[offset + 4] = (byte) (value >> 24); buffer[offset + 5] = (byte) (value >> 16); buffer[offset + 6] = (byte) (value >> 8); buffer[offset + 7] = (byte) value; } } /** * Big endian, 32 bit array encoder */ private static final class BE32ArrayIO extends BigEndianArrayIO { static final ArrayIO INSTANCE = new BE32ArrayIO(); public void putAddress(byte[] buffer, int offset, long value) { buffer[offset + 0] = (byte) (value >> 24); buffer[offset + 1] = (byte) (value >> 16); buffer[offset + 2] = (byte) (value >> 8); buffer[offset + 3] = (byte) value; } } /** * Big endian, 64 bit array encoder */ private static final class BE64ArrayIO extends BigEndianArrayIO { static final ArrayIO INSTANCE = new BE64ArrayIO(); public void putAddress(byte[] buffer, int offset, long value) { putLong(buffer, offset, value); } } private static final class InvalidArrayIO extends ArrayIO { private final Throwable error; InvalidArrayIO(Throwable error) { this.error = error; } private RuntimeException ex() { RuntimeException ule = new RuntimeException("could not determine native data encoding"); ule.initCause(error); return ule; } @Override public void putByte(byte[] buffer, int offset, int value) { throw ex(); } @Override public void putShort(byte[] buffer, int offset, int value) { throw ex(); } @Override public void putInt(byte[] buffer, int offset, int value) { throw ex(); } @Override public void putLong(byte[] buffer, int offset, long value) { throw ex(); } @Override public void putAddress(byte[] buffer, int offset, long value) { throw ex(); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/HeapObjectParameterInvoker.java000066400000000000000000000313521247047424400257400ustar00rootroot00000000000000package com.kenai.jffi; /** * */ final class HeapObjectParameterInvoker extends ObjectParameterInvoker { private final Foreign foreign; HeapObjectParameterInvoker(Foreign foreign) { this.foreign = foreign; } public final boolean isNative() { return false; } private static int encode(HeapInvocationBuffer.Encoder encoder, byte[] paramBuffer, int off, Type type, long n) { if (type.size() <= 4) { return encoder.putInt(paramBuffer, off, (int) n); } else { return encoder.putLong(paramBuffer, off, n); } } private long invokeO1(Function function, byte[] paramBuffer, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return function.getReturnType().size() == 8 ? foreign.invokeArrayO1Int64(function.getContextAddress(), function.getFunctionAddress(), paramBuffer, o1, o1flags.asObjectInfo(), o1off, o1len) : foreign.invokeArrayO1Int32(function.getContextAddress(), function.getFunctionAddress(), paramBuffer, o1, o1flags.asObjectInfo(), o1off, o1len); } private long invokeO2(Function function, byte[] paramBuffer, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return function.getReturnType().size() == 8 ? foreign.invokeArrayO2Int64(function.getContextAddress(), function.getFunctionAddress(), paramBuffer, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len) : foreign.invokeArrayO2Int32(function.getContextAddress(), function.getFunctionAddress(), paramBuffer, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len); } private long invokeO3(Function function, byte[] paramBuffer, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { int[] objInfo = { o1flags.asObjectInfo(), o1off, o1len, o2flags.asObjectInfo(), o2off, o2len, o3flags.asObjectInfo(), o3off, o3len }; Object[] objects = { o1, o2, o3 }; return function.getReturnType().size() == 8 ? foreign.invokeArrayWithObjectsInt64(function.getContextAddress(), function.getFunctionAddress(), paramBuffer, 3, objInfo, objects) : foreign.invokeArrayWithObjectsInt32(function.getContextAddress(), function.getFunctionAddress(), paramBuffer, 3, objInfo, objects); } public long invokeN1O1rN(Function function, long n1, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return invokeO1(function, new byte[HeapInvocationBuffer.Encoder.getInstance().getBufferSize(function.getCallContext())], o1, o1off, o1len, o1flags); } public long invokeN2O1rN(Function function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { HeapInvocationBuffer.Encoder encoder = HeapInvocationBuffer.Encoder.getInstance(); byte[] paramBuffer = new byte[encoder.getBufferSize(function.getCallContext())]; int poff = 0; poff = encode(encoder, paramBuffer, poff, function.getParameterType(0), n1); encode(encoder, paramBuffer, poff, function.getParameterType(1), n2); return invokeO1(function, paramBuffer, o1, o1off, o1len, o1flags); } public long invokeN2O2rN(Function function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return invokeO2(function, new byte[HeapInvocationBuffer.Encoder.getInstance().getBufferSize(function.getCallContext())], o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags); } private static byte[] encodeN3(Function function, long n1, long n2, long n3) { HeapInvocationBuffer.Encoder encoder = HeapInvocationBuffer.Encoder.getInstance(); byte[] paramBuffer = new byte[encoder.getBufferSize(function.getCallContext())]; int poff = 0; poff = encode(encoder, paramBuffer, poff, function.getParameterType(0), n1); poff = encode(encoder, paramBuffer, poff, function.getParameterType(1), n2); encode(encoder, paramBuffer, poff, function.getParameterType(2), n3); return paramBuffer; } public long invokeN3O1rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return invokeO1(function, encodeN3(function, n1, n2, n3), o1, o1off, o1len, o1flags); } public long invokeN3O2rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return invokeO2(function, encodeN3(function, n1, n2, n3), o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags); } public long invokeN3O3rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { return invokeO3(function, encodeN3(function, n1, n2, n3), o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags, o3, o3off, o3len, o3flags); } private static byte[] encodeN4(Function function, long n1, long n2, long n3, long n4) { HeapInvocationBuffer.Encoder encoder = HeapInvocationBuffer.Encoder.getInstance(); byte[] paramBuffer = new byte[encoder.getBufferSize(function.getCallContext())]; int poff = 0; poff = encode(encoder, paramBuffer, poff, function.getParameterType(0), n1); poff = encode(encoder, paramBuffer, poff, function.getParameterType(1), n2); poff = encode(encoder, paramBuffer, poff, function.getParameterType(2), n3); encode(encoder, paramBuffer, poff, function.getParameterType(3), n4); return paramBuffer; } public long invokeN4O1rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return invokeO1(function, encodeN4(function, n1, n2, n3, n4), o1, o1off, o1len, o1flags); } public long invokeN4O2rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return invokeO2(function, encodeN4(function, n1, n2, n3, n4), o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags); } public long invokeN4O3rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { return invokeO3(function, encodeN4(function, n1, n2, n3, n4), o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags, o3, o3off, o3len, o3flags); } private static byte[] encodeN5(Function function, long n1, long n2, long n3, long n4, long n5) { HeapInvocationBuffer.Encoder encoder = HeapInvocationBuffer.Encoder.getInstance(); byte[] paramBuffer = new byte[encoder.getBufferSize(function.getCallContext())]; int poff = 0; poff = encode(encoder, paramBuffer, poff, function.getParameterType(0), n1); poff = encode(encoder, paramBuffer, poff, function.getParameterType(1), n2); poff = encode(encoder, paramBuffer, poff, function.getParameterType(2), n3); poff = encode(encoder, paramBuffer, poff, function.getParameterType(3), n4); encode(encoder, paramBuffer, poff, function.getParameterType(4), n5); return paramBuffer; } @Override public long invokeN5O1rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return invokeO1(function, encodeN5(function, n1, n2, n3, n4, n5), o1, o1off, o1len, o1flags); } @Override public long invokeN5O2rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return invokeO2(function, encodeN5(function, n1, n2, n3, n4, n5), o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags); } public long invokeN5O3rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { return invokeO3(function, encodeN5(function, n1, n2, n3, n4, n5), o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags, o3, o3off, o3len, o3flags); } private static byte[] encodeN6(Function function, long n1, long n2, long n3, long n4, long n5, long n6) { HeapInvocationBuffer.Encoder encoder = HeapInvocationBuffer.Encoder.getInstance(); byte[] paramBuffer = new byte[encoder.getBufferSize(function.getCallContext())]; int poff = 0; poff = encode(encoder, paramBuffer, poff, function.getParameterType(0), n1); poff = encode(encoder, paramBuffer, poff, function.getParameterType(1), n2); poff = encode(encoder, paramBuffer, poff, function.getParameterType(2), n3); poff = encode(encoder, paramBuffer, poff, function.getParameterType(3), n4); poff = encode(encoder, paramBuffer, poff, function.getParameterType(4), n5); encode(encoder, paramBuffer, poff, function.getParameterType(5), n6); return paramBuffer; } @Override public long invokeN6O1rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return invokeO1(function, encodeN6(function, n1, n2, n3, n4, n5, n6), o1, o1off, o1len, o1flags); } @Override public long invokeN6O2rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return invokeO2(function, encodeN6(function, n1, n2, n3, n4, n5, n6), o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags); } public long invokeN6O3rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { return invokeO3(function, encodeN6(function, n1, n2, n3, n4, n5, n6), o1, o1off, o1len, o1flags, o2, o2off, o2len, o2flags, o3, o3off, o3len, o3flags); } } jffi-1.2.7/src/main/java/com/kenai/jffi/Init.java000066400000000000000000000110261247047424400214340ustar00rootroot00000000000000/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Utility class to load the jffi stub library */ final class Init { private static volatile boolean loaded = false; static final String stubLoaderClassName = Init.class.getPackage().getName() + ".internal.StubLoader"; // prevent instantiation private Init() {} /** * Loads the stub library */ static void load() { if (loaded) { return; } List failureCauses = new ArrayList(); List loaders = getClassLoaders(); for (ClassLoader cl : loaders) { try { Class c = Class.forName(stubLoaderClassName, true, cl); Method isLoaded = c.getDeclaredMethod("isLoaded", new Class[0]); loaded |= Boolean.class.cast(isLoaded.invoke(c, new Object[0])); if (!loaded) { Method getFailureCause = c.getDeclaredMethod("getFailureCause", new Class[0]); throw Throwable.class.cast(getFailureCause.invoke(c, new Object[0])); } } catch (IllegalAccessException ex) { failureCauses.add(ex); } catch (InvocationTargetException ex) { failureCauses.add(ex); } catch (ClassNotFoundException ex) { failureCauses.add(ex); } catch (Throwable throwable) { if (throwable instanceof UnsatisfiedLinkError) { throw (UnsatisfiedLinkError) throwable; } throw newLoadError(throwable); } } if (!loaded && !failureCauses.isEmpty()) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); for (Throwable t : failureCauses) { t.printStackTrace(pw); } throw new UnsatisfiedLinkError(sw.toString()); } } private static List getClassLoaders() { List loaders = new ArrayList(); try { loaders.add(ClassLoader.getSystemClassLoader()); } catch (SecurityException ex) { } try { loaders.add(Thread.currentThread().getContextClassLoader()); } catch (SecurityException ex) { } loaders.add(Init.class.getClassLoader()); // Remove all the nulls except one - in the case where this is loaded // from the bootstrap classloader int nullCount = 0; for (Iterator it = loaders.iterator(); it.hasNext(); ) { if (it.next() == null && ++nullCount > 1) { it.remove(); } } return Collections.unmodifiableList(loaders); } private static UnsatisfiedLinkError newLoadError(Throwable cause) { UnsatisfiedLinkError error = new UnsatisfiedLinkError(); error.initCause(cause); return error; } } jffi-1.2.7/src/main/java/com/kenai/jffi/Internals.java000066400000000000000000000030221247047424400224650ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Retrieves metadata about jffi C internals */ public final class Internals { private Internals() { } public static final long getErrnoSaveFunction() { return Foreign.getInstance().getSaveErrnoFunction(); } } jffi-1.2.7/src/main/java/com/kenai/jffi/InvocationBuffer.java000066400000000000000000000137361247047424400240060ustar00rootroot00000000000000/* * Copyright (C) 2007-2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.nio.Buffer; /** * A parameter buffer used when invoking a function */ public abstract class InvocationBuffer { /** * Adds an 8 bit integer parameter. * * @param value An 8 bit integer value to use as the parameter. */ public abstract void putByte(final int value); /** * Adds a 16 bit integer parameter. * * @param value A 16 bit integer value to use as the parameter. */ public abstract void putShort(final int value); /** * Adds a 32 bit integer parameter. * * @param value A 32 bit integer value to use as the parameter. */ public abstract void putInt(final int value); /** * Adds a 64 bit integer parameter. * * @param value A 64 bit integer value to use as the parameter. */ public abstract void putLong(final long value); /** * Adds a 32 bit floating point parameter. * * @param value A 32 bit floating point value to use as the parameter. */ public abstract void putFloat(final float value); /** * Adds a 64 bit floating point parameter. * * @param value A 64 bit floating point value to use as the parameter. */ public abstract void putDouble(final double value); /** * Adds a native address parameter. * * @param value A native address value to use as the parameter. */ public abstract void putAddress(final long value); /** * Adds a java byte array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final byte[] value, int offset, int length, int flags); /** * Adds a java short array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final short[] value, int offset, int length, int flags); /** * Adds a java int array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final int[] value, int offset, int length, int flags); /** * Adds a java long array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final long[] value, int offset, int length, int flags); /** * Adds a java float array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final float[] value, int offset, int length, int flags); /** * Adds a java double array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final double[] value, int offset, int length, int flags); /** * Adds a java direct buffer as a pointer parameter. * @param buffer The buffer to use as a pointer argument. * @param offset An offset to add to the buffer native address. * @param length The length of the buffer to use. */ public abstract void putDirectBuffer(final Buffer buffer, int offset, int length); /** * Adds a struct or union as a parameter. * * This passes the struct or union by value, not by reference. * * @param struct A java byte array with the struct contents. * @param offset The offset from the start of the array. */ public abstract void putStruct(final byte[] struct, int offset); /** * Adds a struct or union as a parameter. * * This passes the struct or union by value, not by reference. * * @param struct The native address to use as the struct contents. */ public abstract void putStruct(final long struct); } jffi-1.2.7/src/main/java/com/kenai/jffi/InvokeDynamicSupport.java000066400000000000000000000140661247047424400246750ustar00rootroot00000000000000package com.kenai.jffi; import java.lang.reflect.Method; import java.util.Arrays; /** * Provide a factory for invokedynamic handles that are bound to a particular call context+function */ public final class InvokeDynamicSupport { private InvokeDynamicSupport() {} public static final class Invoker { private final Method method; private final Object methodHandle; Invoker(Method method, Object methodHandle) { this.method = method; this.methodHandle = methodHandle; } public Object getMethodHandle() { return methodHandle; } public Method getMethod() { return method; } } public static Invoker getFastNumericInvoker(CallContext callContext, long function) { Platform.CPU cpu = Platform.getPlatform().getCPU(); if (!(callContext.getReturnType() instanceof Type.Builtin)) { return null; } if ((callContext.flags & Foreign.F_STDCALL) != 0) { return null; } if (callContext.getParameterCount() > 6) { return null; } boolean isFastInt = false, isFastLong = false; switch (callContext.getReturnType().type()) { case Foreign.TYPE_SINT8: case Foreign.TYPE_UINT8: case Foreign.TYPE_SINT16: case Foreign.TYPE_UINT16: case Foreign.TYPE_SINT32: case Foreign.TYPE_UINT32: isFastInt = true; isFastLong = cpu.dataModel == 64; break; case Foreign.TYPE_POINTER: isFastInt = cpu.dataModel == 32; isFastLong = cpu.dataModel == 64; break; case Foreign.TYPE_SINT64: case Foreign.TYPE_UINT64: isFastLong = true; break; case Foreign.TYPE_STRUCT: return null; case Foreign.TYPE_VOID: isFastInt = isFastLong = true; break; } isFastInt &= (cpu == Platform.CPU.I386 || cpu == Platform.CPU.X86_64); isFastLong &= (cpu == Platform.CPU.I386 || cpu == Platform.CPU.X86_64); for (int i = 0; i < callContext.getParameterCount() && (isFastInt || isFastLong); i++) { if (!(callContext.getParameterType(i) instanceof Type.Builtin)) { return null; } switch (callContext.getParameterType(i).type()) { case Foreign.TYPE_SINT8: case Foreign.TYPE_UINT8: case Foreign.TYPE_SINT16: case Foreign.TYPE_UINT16: case Foreign.TYPE_SINT32: case Foreign.TYPE_UINT32: isFastLong &= cpu.dataModel == 64; break; case Foreign.TYPE_SINT64: case Foreign.TYPE_UINT64: isFastInt = false; break; case Foreign.TYPE_POINTER: isFastInt &= cpu.dataModel == 32; isFastLong &= cpu.dataModel == 64; break; case Foreign.TYPE_STRUCT: return null; default: isFastInt = isFastLong = false; break; } } Class nativeIntClass = isFastInt ? int.class : long.class; String methodName = (isFastInt ? "invokeI" : isFastLong ? "invokeL" : "invokeN") + callContext.getParameterCount(); if ((callContext.flags & Foreign.F_NOERRNO) != 0 && (isFastInt || isFastLong)) { methodName += "NoErrno"; } Class[] params = new Class[2 + callContext.getParameterCount()]; params[0] = long.class; params[1] = long.class; Arrays.fill(params, 2, params.length, nativeIntClass); try { Method method = Foreign.class.getDeclaredMethod(methodName, params); JSR292 jsr292 = JSR292.INSTANCE; Object methodHandle = jsr292.insertArguments(jsr292.unreflect(method), 0, callContext.getAddress(), function); return new Invoker(method, methodHandle); } catch (Throwable ex) { return null; } } static final class JSR292 { static final JSR292 INSTANCE = getInstance(); static boolean isAvailable() { return INSTANCE != null; } private static JSR292 getInstance() { try { Class lookupClass = Class.forName("java.lang.invoke.MethodHandles$Lookup"); Class methodHandlesClass = Class.forName("java.lang.invoke.MethodHandles"); Class methodHandleClass = Class.forName("java.lang.invoke.MethodHandle"); Method lookupMethod = methodHandlesClass.getDeclaredMethod("lookup"); Method unreflect = lookupClass.getDeclaredMethod("unreflect", Method.class); Method insertArguments = methodHandlesClass.getDeclaredMethod("insertArguments", methodHandleClass, int.class, Object[].class); Object lookup = lookupMethod.invoke(methodHandlesClass); return new JSR292(lookup, unreflect, methodHandlesClass, insertArguments); } catch (Throwable t) { return null; } } private final Object lookup; private final Method unreflect; private final Class methodHandles; private final Method insertArguments; JSR292(Object lookup, Method unreflect, Class methodHandles, Method insertArguments) { this.lookup = lookup; this.unreflect = unreflect; this.methodHandles = methodHandles; this.insertArguments = insertArguments; } public Object unreflect(Method m) throws Exception { return unreflect.invoke(lookup, m); } public Object insertArguments(Object methodHandle, int index, Object... values) throws Exception { return insertArguments.invoke(methodHandles, methodHandle, index, values); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/Invoker.java000066400000000000000000003100671247047424400221550ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.math.BigDecimal; /** * Provides native function invocation facilities. */ public abstract class Invoker { private final Foreign foreign; private final ObjectParameterInvoker objectParameterInvoker; /** Lazy initialization singleton holder */ private static final class SingletonHolder { private static final Invoker INSTANCE = Platform.getPlatform().addressSize() == 64 ? LP64.INSTANCE : ILP32.INSTANCE; } /** * Gets the Invoker singleton. * * @return An instance of Invoker. */ public static Invoker getInstance() { return SingletonHolder.INSTANCE; } /** Creates a new Invoker */ private Invoker() { this(Foreign.getInstance(), ObjectParameterInvoker.getInstance()); } Invoker(Foreign foreign, ObjectParameterInvoker objectParameterInvoker) { this.foreign = foreign; this.objectParameterInvoker = objectParameterInvoker; } /** * Gets the fast-path object parameter invoker. * * @return An instance of {@link ObjectParameterInvoker} */ public final ObjectParameterInvoker getObjectParameterInvoker() { return objectParameterInvoker; } /** * Invokes a function with no arguments, and returns a 32 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @return A 32 bit integer value. */ public final int invokeI0(CallContext context, long function) { return Foreign.invokeI0(context.contextAddress, function); } /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 A 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeI1(CallContext context, long function, int arg1) { return Foreign.invokeI1(context.contextAddress, function, arg1); } /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeI2(CallContext context, long function, int arg1, int arg2) { return Foreign.invokeI2(context.contextAddress, function, arg1, arg2); } /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeI3(CallContext context, long function, int arg1, int arg2, int arg3) { return Foreign.invokeI3(context.contextAddress, function, arg1, arg2, arg3); } /** * Invokes a function with four integer arguments, and returns a 32 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeI4(CallContext context, long function, int arg1, int arg2, int arg3, int arg4) { return Foreign.invokeI4(context.contextAddress, function, arg1, arg2, arg3, arg4); } /** * Invokes a function with five integer arguments, and returns a 32 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @param arg5 The fifth 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeI5(CallContext context, long function, int arg1, int arg2, int arg3, int arg4, int arg5) { return Foreign.invokeI5(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5); } /** * Invokes a function with six integer arguments, and returns a 32 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @param arg5 The fifth 32 bit integer argument. * @param arg6 The sixth 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeI6(CallContext context, long function, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) { return Foreign.invokeI6(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5, arg6); } public final int invokeI0NoErrno(CallContext context, long function) { return Foreign.invokeI0NoErrno(context.contextAddress, function); } public final int invokeI1NoErrno(CallContext context, long function, int arg1) { return Foreign.invokeI1NoErrno(context.contextAddress, function, arg1); } public final int invokeI2NoErrno(CallContext context, long function, int arg1, int arg2) { return Foreign.invokeI2NoErrno(context.contextAddress, function, arg1, arg2); } public final int invokeI3NoErrno(CallContext context, long function, int arg1, int arg2, int arg3) { return Foreign.invokeI3NoErrno(context.contextAddress, function, arg1, arg2, arg3); } public final int invokeI4NoErrno(CallContext context, long function, int arg1, int arg2, int arg3, int arg4) { return Foreign.invokeI4NoErrno(context.contextAddress, function, arg1, arg2, arg3, arg4); } public final int invokeI5NoErrno(CallContext context, long function, int arg1, int arg2, int arg3, int arg4, int arg5) { return Foreign.invokeI5NoErrno(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5); } public final int invokeI6NoErrno(CallContext context, long function, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) { return Foreign.invokeI6NoErrno(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5, arg6); } /** * Invokes a function with no arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @return A 32 bit integer value. */ @Deprecated public final int invokeVrI(Function function) { return Foreign.invokeI0(function.contextAddress, function.functionAddress); } /** * Invokes a function with no arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The Function to invoke. * @return A 32 bit integer value. */ @Deprecated public final int invokeNoErrnoVrI(Function function) { return Foreign.invokeI0NoErrno(function.contextAddress, function.functionAddress); } /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 A 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeIrI(Function function, int arg1) { return Foreign.invokeI1(function.contextAddress, function.functionAddress, arg1); } /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The Function to invoke. * @param arg1 A 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeNoErrnoIrI(Function function, int arg1) { return Foreign.invokeI1NoErrno(function.contextAddress, function.functionAddress, arg1); } /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeIIrI(Function function, int arg1, int arg2) { return Foreign.invokeI2(function.contextAddress, function.functionAddress, arg1, arg2); } /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeNoErrnoIIrI(Function function, int arg1, int arg2) { return Foreign.invokeI2NoErrno(function.contextAddress, function.functionAddress, arg1, arg2); } /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeIIIrI(Function function, int arg1, int arg2, int arg3) { return Foreign.invokeI3(function.contextAddress, function.functionAddress, arg1, arg2, arg3); } /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeNoErrnoIIIrI(Function function, int arg1, int arg2, int arg3) { return Foreign.invokeI3NoErrno(function.contextAddress, function.functionAddress, arg1, arg2, arg3); } /** * Invokes a function with four integer arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeIIIIrI(Function function, int arg1, int arg2, int arg3, int arg4) { return Foreign.invokeI4(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4); } /** * Invokes a function with five integer arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @param arg5 The fifth 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeIIIIIrI(Function function, int arg1, int arg2, int arg3, int arg4, int arg5) { return Foreign.invokeI5(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4, arg5); } /** * Invokes a function with six integer arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @param arg5 The fifth 32 bit integer argument. * @param arg6 The sixth 32 bit integer argument. * @return A 32 bit integer value. */ @Deprecated public final int invokeIIIIIIrI(Function function, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) { return Foreign.invokeI6(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4, arg5, arg6); } /** * Invokes a function with no arguments, and returns a 64 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @return A 64 bit integer value. */ public final long invokeL0(CallContext context, long function) { return Foreign.invokeL0(context.contextAddress, function); } /** * Invokes a function with one 64 bit integer argument, and returns a 64 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeL1(CallContext context, long function, long arg1) { return Foreign.invokeL1(context.contextAddress, function, arg1); } /** * Invokes a function with two 64 bit integer arguments, and returns a 64 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeL2(CallContext context, long function, long arg1, long arg2) { return Foreign.invokeL2(context.contextAddress, function, arg1, arg2); } /** * Invokes a function with three 64 bit integer arguments, and returns a 64 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeL3(CallContext context, long function, long arg1, long arg2, long arg3) { return Foreign.invokeL3(context.contextAddress, function, arg1, arg2, arg3); } /** * Invokes a function with four 64 bit integer arguments, and returns a 64 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeL4(CallContext context, long function, long arg1, long arg2, long arg3, long arg4) { return Foreign.invokeL4(context.contextAddress, function, arg1, arg2, arg3, arg4); } /** * Invokes a function with five 64 bit integer arguments, and returns a 64 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeL5(CallContext context, long function, long arg1, long arg2, long arg3, long arg4, long arg5) { return Foreign.invokeL5(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5); } /** * Invokes a function with six 64 bit integer arguments, and returns a 64 bit integer. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @param arg6 The sixth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeL6(CallContext context, long function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { return Foreign.invokeL6(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5, arg6); } public final long invokeL0NoErrno(CallContext context, long function) { return Foreign.invokeL0NoErrno(context.contextAddress, function); } public final long invokeL1NoErrno(CallContext context, long function, long arg1) { return Foreign.invokeL1NoErrno(context.contextAddress, function, arg1); } public final long invokeL2NoErrno(CallContext context, long function, long arg1, long arg2) { return Foreign.invokeL2NoErrno(context.contextAddress, function, arg1, arg2); } public final long invokeL3NoErrno(CallContext context, long function, long arg1, long arg2, long arg3) { return Foreign.invokeL3NoErrno(context.contextAddress, function, arg1, arg2, arg3); } public final long invokeL4NoErrno(CallContext context, long function, long arg1, long arg2, long arg3, long arg4) { return Foreign.invokeL4NoErrno(context.contextAddress, function, arg1, arg2, arg3, arg4); } public final long invokeL5NoErrno(CallContext context, long function, long arg1, long arg2, long arg3, long arg4, long arg5) { return Foreign.invokeL5NoErrno(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5); } public final long invokeL6NoErrno(CallContext context, long function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { return Foreign.invokeL6NoErrno(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5, arg6); } /** * Invokes a function with no arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @return A 64 bit integer value. */ public final long invokeVrL(Function function) { return Foreign.invokeL0(function.contextAddress, function.functionAddress); } /** * Invokes a function with one 64 bit integer argument, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLrL(Function function, long arg1) { return Foreign.invokeL1(function.contextAddress, function.functionAddress, arg1); } /** * Invokes a function with two 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLrL(Function function, long arg1, long arg2) { return Foreign.invokeL2(function.contextAddress, function.functionAddress, arg1, arg2); } /** * Invokes a function with three 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLLrL(Function function, long arg1, long arg2, long arg3) { return Foreign.invokeL3(function.contextAddress, function.functionAddress, arg1, arg2, arg3); } /** * Invokes a function with four 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLLLrL(Function function, long arg1, long arg2, long arg3, long arg4) { return Foreign.invokeL4(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4); } /** * Invokes a function with five 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLLLLrL(Function function, long arg1, long arg2, long arg3, long arg4, long arg5) { return Foreign.invokeL5(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4, arg5); } /** * Invokes a function with six 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @param arg6 The sixth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLLLLLrL(Function function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { return Foreign.invokeL6(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4, arg5, arg6); } /** * Invokes a function with no arguments, and returns a numeric value. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @return A numeric value. */ public final long invokeN0(CallContext context, long function) { return Foreign.invokeN0(context.contextAddress, function); } /** * Invokes a function with one numeric argument, and returns a numeric value. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The numeric argument. * @return A numeric value. */ public final long invokeN1(CallContext context, long function, long arg1) { return Foreign.invokeN1(context.contextAddress, function, arg1); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @return A numeric value. */ public final long invokeN2(CallContext context, long function, long arg1, long arg2) { return Foreign.invokeN2(context.contextAddress, function, arg1, arg2); } /** * Invokes a function with three numeric arguments, and returns a numeric value. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @return A numeric value. */ public final long invokeN3(CallContext context, long function, long arg1, long arg2, long arg3) { return Foreign.invokeN3(context.contextAddress, function, arg1, arg2, arg3); } /** * Invokes a function with four numeric arguments, and returns a numeric value. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @return A numeric value. */ public final long invokeN4(CallContext context, long function, long arg1, long arg2, long arg3, long arg4) { return Foreign.invokeN4(context.contextAddress, function, arg1, arg2, arg3, arg4); } /** * Invokes a function with five numeric arguments, and returns a numeric value. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @return A numeric value. */ public final long invokeN5(CallContext context, long function, long arg1, long arg2, long arg3, long arg4, long arg5) { return Foreign.invokeN5(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5); } /** * Invokes a function with six numeric arguments, and returns a numeric value. * * @param context The CallContext describing how to invoke the function. * @param function Address of the native function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @param arg6 The sixth numeric argument. * @return A numeric value. */ public final long invokeN6(CallContext context, long function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { return Foreign.invokeN6(context.contextAddress, function, arg1, arg2, arg3, arg4, arg5, arg6); } /** * Invokes a function with no arguments, and returns a numeric value. * * @param function The Function to invoke. * @return A numeric value. */ public final long invokeVrN(Function function) { return Foreign.invokeN0(function.contextAddress, function.functionAddress); } /** * Invokes a function with one numeric argument, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The numeric argument. * @return A numeric value. */ public final long invokeNrN(Function function, long arg1) { return Foreign.invokeN1(function.contextAddress, function.functionAddress, arg1); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @return A numeric value. */ public final long invokeNNrN(Function function, long arg1, long arg2) { return Foreign.invokeN2(function.contextAddress, function.functionAddress, arg1, arg2); } /** * Invokes a function with three numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @return A numeric value. */ public final long invokeNNNrN(Function function, long arg1, long arg2, long arg3) { return Foreign.invokeN3(function.contextAddress, function.functionAddress, arg1, arg2, arg3); } /** * Invokes a function with four numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @return A numeric value. */ public final long invokeNNNNrN(Function function, long arg1, long arg2, long arg3, long arg4) { return Foreign.invokeN4(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4); } /** * Invokes a function with five numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @return A numeric value. */ public final long invokeNNNNNrN(Function function, long arg1, long arg2, long arg3, long arg4, long arg5) { return Foreign.invokeN5(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4, arg5); } /** * Invokes a function with six numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @param arg6 The sixth numeric argument. * @return A numeric value. */ public final long invokeNNNNNNrN(Function function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { return Foreign.invokeN6(function.contextAddress, function.functionAddress, arg1, arg2, arg3, arg4, arg5, arg6); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 first numeric argument. * @param n2 second numeric argument. * @param o1 array or buffer, to be passed as a pointer for the first numeric parameter. * @param o1off offset from the start of the array pr buffer. * @param o1len length of the array to use. * @param o1flags object flags (type, direction, parameter index). */ @Deprecated public final long invokeNNO1rN(Function function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return Foreign.invokeN2O1(function.contextAddress, function.functionAddress, n1, n2, o1, o1flags.asObjectInfo(), o1off, o1len); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 first numeric argument. * @param n2 second numeric argument. * @param o1 array or buffer, to be passed as a pointer for the first numeric parameter. * @param o1off offset from the start of the array pr buffer. * @param o1len length of the array to use. * @param o1flags object flags (type, direction, parameter index). */ @Deprecated public final long invokeNNO2rN(Function function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return Foreign.invokeN2O2(function.contextAddress, function.functionAddress, n1, n2, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. */ @Deprecated public final long invokeNNNO1rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return Foreign.invokeN3O1(function.contextAddress, function.functionAddress, n1, n2, n3, o1, o1flags.asObjectInfo(), o1off, o1len); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. */ @Deprecated public final long invokeNNNO2rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return Foreign.invokeN3O2(function.contextAddress, function.functionAddress, n1, n2, n3, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len); } private static RuntimeException newObjectCountError(int objCount) { return new RuntimeException("invalid object count: " + objCount); } private static RuntimeException newInsufficientObjectCountError(int objCount) { return new RuntimeException("invalid object count: " + objCount); } private static RuntimeException newHeapObjectCountError(int objCount) { return new RuntimeException("insufficient number of heap objects supplied (" + objCount + " required)"); } public final long invokeN1O1(CallContext ctx, long function, long n1, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { return Foreign.invokeN1O1(ctx.contextAddress, function, n1, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } public final long invokeN2O1(CallContext ctx, long function, long n1, long n2, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { return Foreign.invokeN2O1(ctx.contextAddress, function, n1, n2, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } public final long invokeN2O2(CallContext ctx, long function, long n1, long n2, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { return Foreign.invokeN2O2(ctx.contextAddress, function, n1, n2, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } public final long invokeN3O1(CallContext ctx, long function, long n1, long n2, long n3, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { return Foreign.invokeN3O1(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } public final long invokeN3O2(CallContext ctx, long function, long n1, long n2, long n3, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { return Foreign.invokeN3O2(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } public final long invokeN3O3(CallContext ctx, long function, long n1, long n2, long n3, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info) { return Foreign.invokeN3O3(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } public final long invokeN4O1(CallContext ctx, long function, long n1, long n2, long n3, long n4, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { return Foreign.invokeN4O1(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } public final long invokeN4O2(CallContext ctx, long function, long n1, long n2, long n3, long n4, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { return Foreign.invokeN4O2(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } public final long invokeN4O3(CallContext ctx, long function, long n1, long n2, long n3, long n4, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info) { return Foreign.invokeN4O3(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } public final long invokeN5O1(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { return Foreign.invokeN5O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } public final long invokeN5O2(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { return Foreign.invokeN5O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } public final long invokeN5O3(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info) { return Foreign.invokeN5O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } public final long invokeN6O1(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { return Foreign.invokeN6O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } public final long invokeN6O2(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { return Foreign.invokeN6O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } public final long invokeN6O3(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info) { return Foreign.invokeN6O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } public final long invokeN1(CallContext ctx, long function, long n1, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { if (objCount == 0) { return Foreign.invokeN1(ctx.contextAddress, function, n1); } else if (objCount == 1) { return Foreign.invokeN1O1(ctx.contextAddress, function, n1, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else { throw newObjectCountError(objCount); } } public final long invokeN2(CallContext ctx, long function, long n1, long n2, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { if (objCount == 0) { return Foreign.invokeN2(ctx.contextAddress, function, n1, n2); } else if (objCount == 1) { return Foreign.invokeN2O1(ctx.contextAddress, function, n1, n2, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else { throw newObjectCountError(objCount); } } public final long invokeN2(CallContext ctx, long function, long n1, long n2, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { if (objCount == 0) { return Foreign.invokeN2(ctx.contextAddress, function, n1, n2); } else if (objCount == 1) { // only one object is to be passed down as a a heap object - figure out which one if (!s1.isDirect()) { // do nothing, use the first param as-is } else if (!s2.isDirect()) { // move second into first place o1 = o2; s1 = s2; o1info = o2info; } return Foreign.invokeN2O1(ctx.contextAddress, function, n1, n2, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else if (objCount == 2) { // Two objects to be passed as heap objects, just use both arguments as-is return Foreign.invokeN2O2(ctx.contextAddress, function, n1, n2, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } else { throw newObjectCountError(objCount); } } public final long invokeN3(CallContext ctx, long function, long n1, long n2, long n3, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { if (objCount == 0) { return Foreign.invokeN3(ctx.contextAddress, function, n1, n2, n3); } else if (objCount == 1) { if (s1.isDirect()) throw newInsufficientObjectCountError(objCount); return Foreign.invokeN3O1(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else { throw newObjectCountError(objCount); } } public final long invokeN3(CallContext ctx, long function, long n1, long n2, long n3, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { if (objCount == 0) { return Foreign.invokeN3(ctx.contextAddress, function, n1, n2, n3); } else if (objCount == 1) { // only one object is to be passed down as a a heap object - figure out which one if (!s1.isDirect()) { // do nothing, use the first param as-is } else if (!s2.isDirect()) { // move second into first place o1 = o2; s1 = s2; o1info = o2info; } return Foreign.invokeN3O1(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else if (objCount == 2) { return Foreign.invokeN3O2(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } else { throw newObjectCountError(objCount); } } public final long invokeN3(CallContext ctx, long function, long n1, long n2, long n3, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info) { if (objCount == 0) { return Foreign.invokeN3(ctx.contextAddress, function, n1, n2, n3); } if (objCount < 3) { int next; // Sort out which is the first non-direct object if (!s1.isDirect()) { // do nothing, use the first param as-is next = 2; } else if (!s2.isDirect()) { // move second into first place o1 = o2; s1 = s2; o1info = o2info; next = 3; } else { // move third into first place o1 = o3; s1 = s3; o1info = o3info; next = 4; } if (objCount == 1) { return Foreign.invokeN3O1(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else if (objCount == 2) { // Sort out which is the second non-direct object if (next <= 2 && !s2.isDirect()) { // do nothing, use the second param as-is } else if (next <= 3) { // move third param into second place o2 = o3; s2 = s3; o2info = o3info; } return Foreign.invokeN3O2(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } else { throw newObjectCountError(objCount); } } // Three objects to be passed as heap objects, just use all arguments as-is return Foreign.invokeN3O3(ctx.contextAddress, function, n1, n2, n3, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } public final long invokeN4(CallContext ctx, long function, long n1, long n2, long n3, long n4, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { if (objCount == 0) { return Foreign.invokeN4(ctx.contextAddress, function, n1, n2, n3, n4); } else if (objCount == 1) { return Foreign.invokeN4O1(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else { throw newObjectCountError(objCount); } } public final long invokeN4(CallContext ctx, long function, long n1, long n2, long n3, long n4, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { if (objCount == 0) { return Foreign.invokeN4(ctx.contextAddress, function, n1, n2, n3, n4); } else if (objCount == 1) { // only one object is to be passed down as a a heap object - figure out which one if (!s1.isDirect()) { // do nothing, use the first param as-is } else if (!s2.isDirect()) { // move second into first place o1 = o2; s1 = s2; o1info = o2info; } return Foreign.invokeN4O1(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else if (objCount == 2) { // Two objects to be passed as heap objects, just use both arguments as-is return Foreign.invokeN4O2(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } else { throw newObjectCountError(objCount); } } public final long invokeN4(CallContext ctx, long function, long n1, long n2, long n3, long n4, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info) { if (objCount == 0) { return Foreign.invokeN4(ctx.contextAddress, function, n1, n2, n3, n4); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } } if (objCount == 1) { return Foreign.invokeN4O1(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } } if (objCount == 2) { return Foreign.invokeN4O2(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: if (!s3.isDirect()) break; default: throw newInsufficientObjectCountError(objCount); } if (objCount == 3) { return Foreign.invokeN4O3(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } throw newObjectCountError(objCount); } public final long invokeN4(CallContext ctx, long function, long n1, long n2, long n3, long n4, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info, Object o4, ObjectParameterStrategy s4, ObjectParameterInfo o4info) { if (objCount == 0) { return Foreign.invokeN4(ctx.contextAddress, function, n1, n2, n3, n4); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o1 = o4; s1 = s4; o1info = o4info; break; } } if (objCount == 1) { return Foreign.invokeN4O1(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o2 = o4; s2 = s4; o2info = o4info; break; } } if (objCount == 2) { return Foreign.invokeN4O2(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: next++; if (!s3.isDirect()) break; case 4: next++; if (!s4.isDirect()) { o3 = o4; s3 = s4; o3info = o4info; break; } } if (objCount == 3) { return Foreign.invokeN4O3(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } if (next != 4 || s4.isDirect()) { throw newInsufficientObjectCountError(objCount); } if (objCount == 4) { return Foreign.invokeN4O4(ctx.contextAddress, function, n1, n2, n3, n4, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4)); } throw newObjectCountError(objCount); } public final long invokeN5(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { if (objCount == 0) { return Foreign.invokeN5(ctx.contextAddress, function, n1, n2, n3, n4, n5); } if (objCount == 1) { return Foreign.invokeN5O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else { throw newObjectCountError(objCount); } } public final long invokeN5(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { if (objCount == 0) { return Foreign.invokeN5(ctx.contextAddress, function, n1, n2, n3, n4, n5); } if (objCount == 1) { // only one object is to be passed down as a a heap object - figure out which one if (!s1.isDirect()) { // do nothing, use the first param as-is } else { // move second into first place o1 = o2; s1 = s2; o1info = o2info; } return Foreign.invokeN5O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else if (objCount == 2) { // Two objects to be passed as heap objects, just use both arguments as-is return Foreign.invokeN5O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } else { throw newObjectCountError(objCount); } } public final long invokeN5(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info) { if (objCount == 0) { return Foreign.invokeN5(ctx.contextAddress, function, n1, n2, n3, n4, n5); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } } if (objCount == 1) { return Foreign.invokeN5O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } } if (objCount == 2) { return Foreign.invokeN5O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: if (!s3.isDirect()) break; } if (objCount == 3) { return Foreign.invokeN5O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } throw newObjectCountError(objCount); } public final long invokeN5(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info, Object o4, ObjectParameterStrategy s4, ObjectParameterInfo o4info) { if (objCount == 0) { return Foreign.invokeN5(ctx.contextAddress, function, n1, n2, n3, n4, n5); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o1 = o4; s1 = s4; o1info = o4info; break; } } if (objCount == 1) { return Foreign.invokeN5O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o2 = o4; s2 = s4; o2info = o4info; break; } } if (objCount == 2) { return Foreign.invokeN5O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: if (!s3.isDirect()) break; case 4: if (!s4.isDirect()) { o3 = o4; s3 = s4; o3info = o4info; break; } } if (objCount == 3) { return Foreign.invokeN5O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } if (objCount == 4) { return Foreign.invokeN5O4(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4)); } throw newObjectCountError(objCount); } public final long invokeN5(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info, Object o4, ObjectParameterStrategy s4, ObjectParameterInfo o4info, Object o5, ObjectParameterStrategy s5, ObjectParameterInfo o5info) { if (objCount == 0) { return Foreign.invokeN5(ctx.contextAddress, function, n1, n2, n3, n4, n5); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o1 = o4; s1 = s4; o1info = o4info; break; } case 5: next++; if (!s5.isDirect()) { o1 = o5; s1 = s5; o1info = o5info; break; } } if (objCount == 1) { return Foreign.invokeN5O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o2 = o4; s2 = s4; o2info = o4info; break; } case 5: next++; if (!s5.isDirect()) { o2 = o5; s2 = s5; o2info = o5info; break; } } if (objCount == 2) { return Foreign.invokeN5O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: next++; if (!s3.isDirect()) break; case 4: next++; if (!s4.isDirect()) { o3 = o4; s3 = s4; o3info = o4info; break; } case 5: next++; if (!s5.isDirect()) { o3 = o5; s3 = s5; o3info = o5info; break; } } if (objCount == 3) { return Foreign.invokeN5O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } switch (next) { case 4: if (!s4.isDirect()) break; case 5: if (!s5.isDirect()) { o4 = o5; s4 = s5; o4info = o5info; break; } } if (objCount == 4) { return Foreign.invokeN5O4(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4)); } if (objCount == 5) { return Foreign.invokeN5O5(ctx.contextAddress, function, n1, n2, n3, n4, n5, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4), s5.object(o5), s5.objectInfo(o5info), s5.offset(o5), s5.length(o5)); } throw newObjectCountError(objCount); } public final long invokeN6(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info) { if (objCount == 0) { return Foreign.invokeN6(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6); } else if (objCount == 1) { return Foreign.invokeN6O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else { throw newObjectCountError(objCount); } } public final long invokeN6(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info) { if (objCount == 0) { return Foreign.invokeN6(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6); } if (objCount == 1) { // only one object is to be passed down as a a heap object - figure out which one if (!s1.isDirect()) { // do nothing, use the first param as-is } else { // move second into first place o1 = o2; s1 = s2; o1info = o2info; } return Foreign.invokeN6O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } else if (objCount == 2) { // Two objects to be passed as heap objects, just use both arguments as-is return Foreign.invokeN6O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } else { throw newObjectCountError(objCount); } } public final long invokeN6(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info) { if (objCount == 0) { return Foreign.invokeN6(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } } if (objCount == 1) { return Foreign.invokeN6O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } } if (objCount == 2) { return Foreign.invokeN6O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: if (!s3.isDirect()) break; } if (objCount == 3) { return Foreign.invokeN6O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } throw newObjectCountError(objCount); } public final long invokeN6(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info, Object o4, ObjectParameterStrategy s4, ObjectParameterInfo o4info) { if (objCount == 0) { return Foreign.invokeN6(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o1 = o4; s1 = s4; o1info = o4info; break; } } if (objCount == 1) { return Foreign.invokeN6O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o2 = o4; s2 = s4; o2info = o4info; break; } } if (objCount == 2) { return Foreign.invokeN6O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: if (!s3.isDirect()) break; case 4: if (!s4.isDirect()) { o3 = o4; s3 = s4; o3info = o4info; break; } } if (objCount == 3) { return Foreign.invokeN6O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } if (objCount == 4) { return Foreign.invokeN6O4(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4)); } throw newObjectCountError(objCount); } public final long invokeN6(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info, Object o4, ObjectParameterStrategy s4, ObjectParameterInfo o4info, Object o5, ObjectParameterStrategy s5, ObjectParameterInfo o5info) { if (objCount == 0) { return Foreign.invokeN6(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o1 = o4; s1 = s4; o1info = o4info; break; } case 5: next++; if (!s5.isDirect()) { o1 = o5; s1 = s5; o1info = o5info; break; } } if (objCount == 1) { return Foreign.invokeN6O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o2 = o4; s2 = s4; o2info = o4info; break; } case 5: next++; if (!s5.isDirect()) { o2 = o5; s2 = s5; o2info = o5info; break; } } if (objCount == 2) { return Foreign.invokeN6O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: if (!s3.isDirect()) break; case 4: if (!s4.isDirect()) { o3 = o4; s3 = s4; o3info = o4info; break; } case 5: if (!s5.isDirect()) { o3 = o5; s3 = s5; o3info = o5info; break; } } if (objCount == 3) { return Foreign.invokeN6O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } switch (next) { case 4: if (!s4.isDirect()) break; case 5: if (!s5.isDirect()) { o4 = o5; s4 = s5; o4info = o5info; break; } } if (objCount == 4) { return Foreign.invokeN6O4(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4)); } if (objCount == 5) { return Foreign.invokeN6O5(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4), s5.object(o5), s5.objectInfo(o5info), s5.offset(o5), s5.length(o5)); } throw newObjectCountError(objCount); } public final long invokeN6(CallContext ctx, long function, long n1, long n2, long n3, long n4, long n5, long n6, int objCount, Object o1, ObjectParameterStrategy s1, ObjectParameterInfo o1info, Object o2, ObjectParameterStrategy s2, ObjectParameterInfo o2info, Object o3, ObjectParameterStrategy s3, ObjectParameterInfo o3info, Object o4, ObjectParameterStrategy s4, ObjectParameterInfo o4info, Object o5, ObjectParameterStrategy s5, ObjectParameterInfo o5info, Object o6, ObjectParameterStrategy s6, ObjectParameterInfo o6info) { if (objCount == 0) { return Foreign.invokeN6(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6); } int next = 1; // Sort out which is the first non-direct object switch (next) { case 1: next++; if (!s1.isDirect()) break; case 2: next++; if (!s2.isDirect()) { o1 = o2; s1 = s2; o1info = o2info; break; } case 3: next++; if (!s3.isDirect()) { o1 = o3; s1 = s3; o1info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o1 = o4; s1 = s4; o1info = o4info; break; } case 5: next++; if (!s5.isDirect()) { o1 = o5; s1 = s5; o1info = o5info; break; } case 6: next++; if (!s6.isDirect()) { o1 = o6; s1 = s6; o1info = o6info; break; } } if (objCount == 1) { return Foreign.invokeN6O1(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1)); } switch (next) { case 2: next++; if (!s2.isDirect()) break; case 3: next++; if (!s3.isDirect()) { o2 = o3; s2 = s3; o2info = o3info; break; } case 4: next++; if (!s4.isDirect()) { o2 = o4; s2 = s4; o2info = o4info; break; } case 5: next++; if (!s5.isDirect()) { o2 = o5; s2 = s5; o2info = o5info; break; } case 6: next++; if (!s6.isDirect()) { o2 = o6; s2 = s6; o2info = o6info; break; } } if (objCount == 2) { return Foreign.invokeN6O2(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2)); } switch (next) { case 3: next++; if (!s3.isDirect()) break; case 4: next++; if (!s4.isDirect()) { o3 = o4; s3 = s4; o3info = o4info; break; } case 5: next++; if (!s5.isDirect()) { o3 = o5; s3 = s5; o3info = o5info; break; } case 6: next++; if (!s6.isDirect()) { o3 = o6; s3 = s6; o3info = o6info; break; } } if (objCount == 3) { return Foreign.invokeN6O3(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3)); } switch (next) { case 4: next++; if (!s4.isDirect()) break; case 5: next++; if (!s5.isDirect()) { o4 = o5; s4 = s5; o4info = o5info; break; } case 6: next++; if (!s6.isDirect()) { o4 = o6; s4 = s6; o4info = o6info; break; } } if (objCount == 4) { return Foreign.invokeN6O4(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4)); } switch (next) { case 5: if (!s5.isDirect()) break; case 6: if (!s6.isDirect()) { o5 = o6; s5 = s6; o5info = o6info; break; } } if (objCount == 5) { return Foreign.invokeN6O5(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4), s5.object(o5), s5.objectInfo(o5info), s5.offset(o5), s5.length(o5)); } if (objCount == 6) { return Foreign.invokeN6O6(ctx.contextAddress, function, n1, n2, n3, n4, n5, n6, s1.object(o1), s1.objectInfo(o1info), s1.offset(o1), s1.length(o1), s2.object(o2), s2.objectInfo(o2info), s2.offset(o2), s2.length(o2), s3.object(o3), s3.objectInfo(o3info), s3.offset(o3), s3.length(o3), s4.object(o4), s4.objectInfo(o4info), s4.offset(o4), s4.length(o4), s5.object(o5), s5.objectInfo(o5info), s5.offset(o5), s5.length(o5), s6.object(o6), s6.objectInfo(o6info), s6.offset(o6), s6.length(o6)); } throw newObjectCountError(objCount); } /** * Invokes a function and returns a native memory address. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public long invokeAddress(Function function, HeapInvocationBuffer buffer) { return invokeAddress(function.getCallContext(), function.getFunctionAddress(), buffer); } /** * Invokes a function and returns a native memory address. * * @param ctx The call context which describes how to call the native function. * @param function The address of the native function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public abstract long invokeAddress(CallContext ctx, long function, HeapInvocationBuffer buffer); /** * Invokes a function and returns a 32 bit integer value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final int invokeInt(Function function, HeapInvocationBuffer buffer) { return invokeInt(function.getCallContext(), function.getFunctionAddress(), buffer); } /** * Invokes a function and returns a 32 bit integer value. * * @param ctx The call context which describes how to call the native function. * @param function The address of the native function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final int invokeInt(CallContext ctx, long function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return objectBuffer != null ? invokeArrayWithObjectsInt32(ctx.contextAddress, function, buffer, objectBuffer) : Foreign.invokeArrayReturnInt(ctx.contextAddress, function, buffer.array()); } /** * Invokes a function and returns a 64 bit integer value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final long invokeLong(Function function, HeapInvocationBuffer buffer) { return invokeLong(function.getCallContext(), function.getFunctionAddress(), buffer); } /** * Invokes a function and returns a 64 bit integer value. * * @param ctx The call context which describes how to call the native function. * @param function The address of the native function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final long invokeLong(CallContext ctx, long function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return objectBuffer != null ? invokeArrayWithObjectsInt64(ctx.contextAddress, function, buffer, objectBuffer) : Foreign.invokeArrayReturnLong(ctx.contextAddress, function, buffer.array()); } /** * Invokes a function and returns a 32 bit floating point value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final float invokeFloat(Function function, HeapInvocationBuffer buffer) { return invokeFloat(function.getCallContext(), function.getFunctionAddress(), buffer); } /** * Invokes a function and returns a 32 bit floating point value. * * @param ctx The call context which describes how to call the native function. * @param function The address of the native function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final float invokeFloat(CallContext ctx, long function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return objectBuffer != null ? Foreign.invokeArrayWithObjectsFloat(ctx.contextAddress, function, buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects()) : Foreign.invokeArrayReturnFloat(ctx.contextAddress, function, buffer.array()); } /** * Invokes a function and returns a 64 bit floating point value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final double invokeDouble(Function function, HeapInvocationBuffer buffer) { return invokeDouble(function.getCallContext(), function.getFunctionAddress(), buffer); } /** * Invokes a function and returns a 64 bit floating point value. * * @param ctx The call context describing how to call the native function. * @param function The address of the native function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final double invokeDouble(CallContext ctx, long function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return objectBuffer != null ? Foreign.invokeArrayWithObjectsDouble(ctx.contextAddress, function, buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects()) : Foreign.invokeArrayReturnDouble(ctx.contextAddress, function, buffer.array()); } /** * Invokes a function and returns a 64 bit floating point value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final BigDecimal invokeBigDecimal(Function function, HeapInvocationBuffer buffer) { return invokeBigDecimal(function.getCallContext(), function.getFunctionAddress(), buffer); } /** * Invokes a function and returns a 64 bit floating point value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final BigDecimal invokeBigDecimal(CallContext ctx, long function, HeapInvocationBuffer buffer) { byte[] rval = invokeStruct(ctx, function, buffer); return new BigDecimal(foreign.longDoubleToString(rval, 0, rval.length)); } /** * Invokes a function that returns a C struct by value. * * @param function The Function to invoke. * @param buffer The parameter buffer. * @return A byte array with the return value encoded in native byte order. */ public final byte[] invokeStruct(Function function, HeapInvocationBuffer buffer) { return invokeStruct(function.getCallContext(), function.getFunctionAddress(), buffer); } /** * Invokes a function that returns a C struct by value. * * @param ctx The call context which describes how to call the native function. * @param function The address of the native function to invoke. * @param buffer The parameter buffer. * @return A byte array with the return value encoded in native byte order. */ public final byte[] invokeStruct(CallContext ctx, long function, HeapInvocationBuffer buffer) { byte[] returnBuffer = new byte[ctx.getReturnType().size()]; invokeStruct(ctx, function, buffer, returnBuffer, 0); return returnBuffer; } /** * Invokes a function that returns a C struct by value. * * @param function The Function to invoke. * @param buffer The parameter buffer. * @param returnBuffer The output buffer to place the return value in. * @param offset The offset within returnBuffer to place the return value. */ public final void invokeStruct(Function function, HeapInvocationBuffer buffer, byte[] returnBuffer, int offset) { invokeStruct(function.getCallContext(), function.getFunctionAddress(), buffer, returnBuffer, offset); } /** * Invokes a function that returns a C struct by value. * * @param ctx The call context which describes how to call the native function. * @param function The address of the native function to invoke. * @param buffer The parameter buffer. * @param returnBuffer The output buffer to place the return value in. * @param offset The offset within returnBuffer to place the return value. */ public final void invokeStruct(CallContext ctx, long function, HeapInvocationBuffer buffer, byte[] returnBuffer, int offset) { ObjectBuffer objectBuffer = buffer.objectBuffer(); if (objectBuffer != null) { Foreign.invokeArrayWithObjectsReturnStruct(ctx.contextAddress, function, buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects(), returnBuffer, offset); } else { Foreign.invokeArrayReturnStruct(ctx.contextAddress, function, buffer.array(), returnBuffer, offset); } } public final Object invokeObject(Function function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return Foreign.invokeArrayWithObjectsReturnObject(function.contextAddress, function.functionAddress, buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects()); } /** * Invokes a function, with the parameters loaded into native memory buffers, * and the function result is stored in a native memory buffer. * * @param function The Function to invoke. * @param returnBuffer The address of the native buffer to place the result * of the function call in. * @param parameters An array of addresses of the function parameters. */ public final void invoke(Function function, long returnBuffer, long[] parameters) { Foreign.invokePointerParameterArray(function.contextAddress, function.functionAddress, returnBuffer, parameters); } /** * Invokes a function, with the parameters loaded into native memory buffers, * and the function result is stored in a native memory buffer. * * @param ctx The call context which describes how to call the native function. * @param function The address of the native function to invoke. * @param returnBuffer The address of the native buffer to place the result * of the function call in. * @param parameters An array of addresses of the function parameters. */ public final void invoke(CallContext ctx, long function, long returnBuffer, long[] parameters) { Foreign.invokePointerParameterArray(ctx.contextAddress, function, returnBuffer, parameters); } /** * Convenience method to pass the objects and object descriptor array down as * normal arguments, so hotspot can optimize it. This is faster than the native * code pulling the objects and descriptors out of arrays. * * @param function The native function to invoke. * @param buffer A buffer containing the arguments to the function. * @param objectBuffer A buffer containing objects to be passed to the native function. * @return A 32 bit integer value. */ private int invokeArrayWithObjectsInt32(long ctx, long function, HeapInvocationBuffer buffer, ObjectBuffer objectBuffer) { Object[] objects = objectBuffer.objects(); int[] info = objectBuffer.info(); int objectCount = objectBuffer.objectCount(); switch (objectCount) { case 1: return Foreign.invokeArrayO1Int32(ctx, function, buffer.array(), objects[0], info[0], info[1], info[2]); case 2: return Foreign.invokeArrayO2Int32(ctx, function, buffer.array(), objects[0], info[0], info[1], info[2], objects[1], info[3], info[4], info[5]); } return Foreign.invokeArrayWithObjectsInt32(ctx, function, buffer.array(), objectCount, info, objects); } /** * Convenience method to pass the objects and object descriptor array down as * normal arguments, so hotspot can optimize it. This is faster than the native * code pulling the objects and descriptors out of arrays. * * @param function The native function to invoke. * @param buffer A buffer containing the arguments to the function. * @param objectBuffer A buffer containing objects to be passed to the native function. * @return A 64 bit integer value. */ private long invokeArrayWithObjectsInt64(long ctx, long function, HeapInvocationBuffer buffer, ObjectBuffer objectBuffer) { Object[] objects = objectBuffer.objects(); int[] info = objectBuffer.info(); int objectCount = objectBuffer.objectCount(); switch (objectCount) { case 1: return Foreign.invokeArrayO1Int64(ctx, function, buffer.array(), objects[0], info[0], info[1], info[2]); case 2: return Foreign.invokeArrayO2Int64(ctx, function, buffer.array(), objects[0], info[0], info[1], info[2], objects[1], info[3], info[4], info[5]); } return Foreign.invokeArrayWithObjectsInt64(ctx, function, buffer.array(), objectCount, info, objects); } /** * A 32 bit invoker implementation */ private static final class ILP32 extends Invoker { private static final Invoker INSTANCE = new ILP32(); /** A mask to apply to native memory addresses to cancel sign extension */ private static final long ADDRESS_MASK = 0xffffffffL; public final long invokeAddress(CallContext ctx, long function, HeapInvocationBuffer buffer) { return ((long)invokeInt(ctx, function, buffer)) & ADDRESS_MASK; } } /** * A 64 bit invoker implementation */ private static final class LP64 extends Invoker { private static final Invoker INSTANCE = new LP64(); public final long invokeAddress(CallContext ctx, long function, HeapInvocationBuffer buffer) { return invokeLong(ctx, function, buffer); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/LastError.java000066400000000000000000000052241247047424400224510ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Provides access to the value of errno on unix, or GetLastError on windows. */ public final class LastError { @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final Foreign foreign = Foreign.getInstance(); /** Lazy-initialization singleton holder */ private static final class SingletonHolder { static final LastError INSTANCE = new LastError(); } /** Creates a new LastError instance */ private LastError() {} /** * Gets the singleton instance of the LastError object. * * @return An instance of LastError */ public static final LastError getInstance() { return SingletonHolder.INSTANCE; } /** * Gets the errno set by the last C function invoked by the current thread. * * @return The value of errno/GetLastError() */ @Deprecated public final int getError() { return Foreign.getLastError(); } /** * Gets the errno set by the last C function invoked by the current thread. * * @return The value of errno/GetLastError() */ public final int get() { return Foreign.getLastError(); } /** * Sets the system errno value. * * @param value The value to set errno to. */ public final void set(int value) { Foreign.setLastError(value); } } jffi-1.2.7/src/main/java/com/kenai/jffi/Library.java000066400000000000000000000150761247047424400221460ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.lang.ref.WeakReference; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Represents a native library */ public final class Library { /** A cache of opened libraries */ private static final Map> cache = new ConcurrentHashMap>(); /** A lock used to serialize all dlopen/dlsym calls */ private static final Object lock = new Object(); /** Stores the last error returned by a dlopen or dlsym call */ private static final ThreadLocal lastError = new ThreadLocal(); /** A handle to the current process */ private static final class DefaultLibrary { private static final Library INSTANCE = openLibrary(null, LAZY | GLOBAL); } /** Perform lazy binding. Only resolve symbols as needed */ public static final int LAZY = Foreign.RTLD_LAZY; /** Resolve all symbols when loading the library */ public static final int NOW = Foreign.RTLD_NOW; /** Symbols in this library are not made available to other libraries */ public static final int LOCAL = Foreign.RTLD_LOCAL; /** All symbols in the library are made available to other libraries */ public static final int GLOBAL = Foreign.RTLD_GLOBAL; /** The native dl/LoadLibrary handle */ private final long handle; /** The name of this Library */ private final String name; /** A handle to the foreign interface to keep it alive as long as this object is alive */ private final Foreign foreign; /** * Internal wrapper around dlopen. * * If the library open fails, then this stores the native error in a thread * local variable for later retrieval. * * @param name The name of the library to open * @param flags The flags to pass to dlopen * @return The native handle for the opened library, or 0 if it failed to open. */ private static long dlopen(Foreign foreign, String name, int flags) { try { return foreign.dlopen(name, flags); } catch (UnsatisfiedLinkError ex) { lastError.set(ex.getMessage()); return 0L; } } /** * Gets a handle to the default library. * * @return A Library instance representing the default library. */ public static final Library getDefault() { return DefaultLibrary.INSTANCE; } /** * Gets a handle for the named library. * * @param name The name or path of the library to open. * @param flags The library flags (e.g. LAZY, NOW, LOCAL, GLOBAL) * @return A Library instance representing the named library, or * null if the library could not be opened. */ public static final Library getCachedInstance(String name, int flags) { if (name == null) { return getDefault(); } WeakReference ref = cache.get(name); Library lib = ref != null ? ref.get() : null; if (lib != null) { return lib; } lib = openLibrary(name, flags); if (lib == null) { return null; } cache.put(name, new WeakReference(lib)); return lib; } /** * Gets a handle for the named library. * * Note This will not cache the instance, nor will it return a cached * instance. Only use when you really need a new handle for the library. * * @param name The name or path of the library to open. * @param flags The library flags (e.g. LAZY, NOW, LOCAL, GLOBAL) * @return A Library instance representing the named library, or * null if the library cannot be opened. */ public static final Library openLibrary(String name, int flags) { // dlopen on some OS does not like flags=0, so set to sensible defaults if (flags == 0) { flags = LAZY | LOCAL; } final Foreign foreign = Foreign.getInstance(); final long address = dlopen(foreign, name, flags); return address != 0L ? new Library(foreign, name, address) : null; } private Library(Foreign foreign, String name, long address) { this.foreign = foreign; this.name = name; this.handle = address; } /** * Gets the address of a symbol within the Library. * * @param name The name of the symbol to locate. * @return The address of the symbol within the current address space. */ public final long getSymbolAddress(String name) { try { return foreign.dlsym(handle, name); } catch (UnsatisfiedLinkError ex) { lastError.set(foreign.dlerror()); return 0; } } /** * Gets the current error string from dlopen/LoadLibrary. * * @return A String describing the last error. */ public static final String getLastError() { String error = lastError.get(); return error != null ? error : "unknown"; } @Override protected void finalize() throws Throwable { try { if (handle != 0L) { foreign.dlclose(handle); } } finally { super.finalize(); } } } jffi-1.2.7/src/main/java/com/kenai/jffi/MemoryIO.java000066400000000000000000001216271247047424400222420ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Provides facilities to access native memory from java. */ public abstract class MemoryIO { /** A handle to the JNI accessor */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) final Foreign foreign = Foreign.getInstance(); /** The address mask used to truncate 32bit addresses contained in long values */ private static final long ADDRESS_MASK = Platform.getPlatform().addressMask(); /** Holds a single instance of MemoryIO */ private static final class SingletonHolder { private static final MemoryIO INSTANCE = newMemoryIO(); } private static final class CheckedMemorySingletonHolder { private static final MemoryIO INSTANCE = newNativeCheckedImpl(); } /** * Gets an instance of MemoryIO that can be used to access native memory. * * @return A MemoryIO instance. */ public static MemoryIO getInstance() { return SingletonHolder.INSTANCE; } public static MemoryIO getCheckedInstance() { return CheckedMemorySingletonHolder.INSTANCE; } /* Restrict construction of instances to subclasses defined in this class only */ private MemoryIO() {} /** * Creates a new instance of MemoryIO optimized for the current platform. * * @return An instance of MemoryIO */ private static MemoryIO newMemoryIO() { try { if (Boolean.getBoolean("jffi.memory.checked")) { return newNativeCheckedImpl(); } // Use sun.misc.Unsafe unless explicitly disabled by the user, or not available return !Boolean.getBoolean("jffi.unsafe.disabled") && isUnsafeAvailable() ? newUnsafeImpl() : newNativeImpl(); } catch (Throwable t) { return newNativeImpl(); } } /* * The new calls are wrapped in methods, so the classes are not referenced * until the method is called. This means only one implementation class * is ever loaded, and hotspot can inline non-final functions implemented * in the subclass. */ private static MemoryIO newNativeImpl() { return Platform.getPlatform().addressSize() == 32 ? newNativeImpl32() : newNativeImpl64(); } private static MemoryIO newNativeCheckedImpl() { return Foreign.isMemoryProtectionEnabled() ? new CheckedNativeImpl() : newNativeImpl(); } /** * Creates a new JNI implementation of MemoryIO optimized for 32 bit platforms * * @return An instance of MemoryIO */ private static MemoryIO newNativeImpl32() { return new NativeImpl32();} /** * Creates a new JNI implementation of MemoryIO optimized for 64 bit platforms * * @return An instance of MemoryIO */ private static MemoryIO newNativeImpl64() { return new NativeImpl64();} /** * Creates a new sun.misc.Unsafe implementation of MemoryIO * * @return An instance of MemoryIO */ private static MemoryIO newUnsafeImpl() { return Platform.getPlatform().addressSize() == 32 ? newUnsafeImpl32() : newUnsafeImpl64(); } /** * Creates a new sun.misc.Unsafe implementation of MemoryIO optimized for 32 bit platforms * * @return An instance of MemoryIO */ private static MemoryIO newUnsafeImpl32() { return new UnsafeImpl32(); } /** * Creates a new sun.misc.Unsafe implementation of MemoryIO optimized for 64 bit platforms * * @return An instance of MemoryIO */ private static MemoryIO newUnsafeImpl64() { return new UnsafeImpl64(); } /** * Reads an 8 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A byte containing the value. */ public abstract byte getByte(long address); /** * Reads a 16 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A short containing the value. */ public abstract short getShort(long address); /** * Reads a 32 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return An int containing the value. */ public abstract int getInt(long address); /** * Reads a 64 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ public abstract long getLong(long address); /** * Reads a 32 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A float containing the value. */ public abstract float getFloat(long address); /** * Reads a 64 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A double containing the value. */ public abstract double getDouble(long address); /** * Reads a native memory address from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ public abstract long getAddress(long address); /** * Writes an 8 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putByte(long address, byte value); /** * Writes a 16 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putShort(long address, short value); /** * Writes a 32 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putInt(long address, int value); /** * Writes a 64 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putLong(long address, long value); /** * Writes a 32 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putFloat(long address, float value); /** * Writes a 64 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putDouble(long address, double value); /** * Writes a native memory address value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putAddress(long address, long value); /** * Copies contents of a native memory location to another native memory location. * * @param src The source memory address. * @param dst The destination memory address. * @param size The number of bytes to copy. */ public final void copyMemory(long src, long dst, long size) { if (dst + size <= src || src + size <= dst) { // Use intrinsic copyMemory if regions do not overlap _copyMemory(src, dst, size); } else { memmove(dst, src, size); } } /** * Copies contents of a native memory location to another native memory location. * * @param src The source memory address. * @param dst The destination memory address. * @param size The number of bytes to copy. */ abstract void _copyMemory(long src, long dst, long size); /** * Sets a region of native memory to a specific byte value. * * @param address The address of start of the native memory. * @param size The number of bytes to set. * @param value The value to set the native memory to. */ public abstract void setMemory(long address, long size, byte value); /** * Copies bytes from one memory location to another. * * The memory areas * * @param dst The destination memory address. * @param src The source memory address. * @param size The number of bytes to copy. */ public abstract void memcpy(long dst, long src, long size); /** * Copies potentially overlapping memory areas. * * @param dst The destination memory address. * @param src The source memory address. * @param size The number of bytes to copy. */ public abstract void memmove(long dst, long src, long size); /** * Sets a region of native memory to a specific byte value. * * @param address The address of start of the native memory. * @param value The value to set the native memory to. * @param size The number of bytes to set. */ public final void memset(long address, int value, long size) { setMemory(address, size, (byte) value); } /** * Gets the address of a byte value in a native memory region. * * @param address The native memory address to start searching. * @param value The value to search for. * @param size The size of the native memory region being searched. * @return The address of the value, or 0 (zero) if not found. */ public abstract long memchr(long address, int value, long size); /** * Writes a java byte array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public abstract void putByteArray(long address, byte[] data, int offset, int length); /** * Reads a java byte array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public abstract void getByteArray(long address, byte[] data, int offset, int length); /** * Writes a java char array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public abstract void putCharArray(long address, char[] data, int offset, int length); /** * Reads a java char array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public abstract void getCharArray(long address, char[] data, int offset, int length); /** * Writes a java short array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public abstract void putShortArray(long address, short[] data, int offset, int length); /** * Reads a java short array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public abstract void getShortArray(long address, short[] data, int offset, int length); /** * Writes a java int array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public abstract void putIntArray(long address, int[] data, int offset, int length); /** * Reads a java int array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public abstract void getIntArray(long address, int[] data, int offset, int length); /** * Writes a java long array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public abstract void putLongArray(long address, long[] data, int offset, int length); /** * Reads a java long array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public abstract void getLongArray(long address, long[] data, int offset, int length); /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public abstract void putFloatArray(long address, float[] data, int offset, int length); /** * Reads a java float array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public abstract void getFloatArray(long address, float[] data, int offset, int length); /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public abstract void putDoubleArray(long address, double[] data, int offset, int length); /** * Reads a java double array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public abstract void getDoubleArray(long address, double[] data, int offset, int length); /** * Allocates native memory. * * @param size The number of bytes of memory to allocate * @param clear Whether the memory should be cleared (each byte set to zero). * @return The native address of the allocated memory. */ public final long allocateMemory(long size, boolean clear) { return Foreign.allocateMemory(size, clear) & ADDRESS_MASK; } /** * Releases memory allocated via {@link #allocateMemory} back to the system. * * @param address The address of the memory to release. */ public final void freeMemory(long address) { Foreign.freeMemory(address); } /** * Gets the length of a native ascii or utf-8 string. * * @param address The native address of the string. * @return The length of the string, in bytes. */ public abstract long getStringLength(long address); /** * Reads a byte array from native memory, stopping when a zero byte is found. * * This can be used to read ascii or utf-8 strings from native memory. * * @param address The address to read the data from. * @return The byte array containing a copy of the native data. Any zero * byte is stripped from the end. */ public abstract byte[] getZeroTerminatedByteArray(long address); /** * Reads a byte array from native memory, stopping when a zero byte is found, * or the maximum length is reached. * * This can be used to read ascii or utf-8 strings from native memory. * * @param address The address to read the data from. * @param maxlen The limit of the memory area to scan for a zero byte. * @return The byte array containing a copy of the native data. Any zero * byte is stripped from the end. */ public abstract byte[] getZeroTerminatedByteArray(long address, int maxlen); @Deprecated public final byte[] getZeroTerminatedByteArray(long address, long maxlen) { return getZeroTerminatedByteArray(address, (int) maxlen); } /** * Copies a java byte array to native memory and appends a NUL terminating byte. * * Note A total of length + 1 bytes is written to native memory. * * @param address The address to copy to. * @param data The byte array to copy to native memory * @param offset The offset within the byte array to begin copying from * @param length The number of bytes to copy to native memory */ public abstract void putZeroTerminatedByteArray(long address, byte[] data, int offset, int length); /** * Finds the location of a byte value in a native memory region. * * @param address The native memory address to start searching from. * @param value The value to search for. * @return The offset from the memory address of the value, if found, else -1 (minus one). */ public final long indexOf(long address, byte value) { final long location = memchr(address, value, Integer.MAX_VALUE); return location != 0 ? location - address : -1; } /** * Finds the location of a byte value in a native memory region. * * @param address The native memory address to start searching from. * @param value The value to search for. * @param maxlen The maximum number of bytes to search. * @return The offset from the memory address of the value, if found, else -1 (minus one). */ public final long indexOf(long address, byte value, int maxlen) { final long location = memchr(address, value, maxlen); return location != 0 ? location - address : -1; } /** * Creates a new Direct ByteBuffer for a native memory region. * * @param address The start of the native memory region. * @param capacity The size of the native memory region. * @return A ByteBuffer representing the native memory region. */ public final java.nio.ByteBuffer newDirectByteBuffer(long address, int capacity) { return foreign.newDirectByteBuffer(address, capacity); } /** * Gets the native memory address of a direct ByteBuffer * * @param buffer A direct ByteBuffer to get the address of. * @return The native memory address of the buffer contents, or null if not a direct buffer. */ public final long getDirectBufferAddress(java.nio.Buffer buffer) { return foreign.getDirectBufferAddress(buffer); } /** * An implementation of MemoryIO using JNI methods. */ private static abstract class NativeImpl extends MemoryIO { public final byte getByte(long address) { return Foreign.getByte(address); } public final short getShort(long address) { return Foreign.getShort(address); } public final int getInt(long address) { return Foreign.getInt(address); } public final long getLong(long address) { return Foreign.getLong(address); } public final float getFloat(long address) { return Foreign.getFloat(address); } public final double getDouble(long address) { return Foreign.getDouble(address); } public final void putByte(long address, byte value) { Foreign.putByte(address, value); } public final void putShort(long address, short value) { Foreign.putShort(address, value); } public final void putInt(long address, int value) { Foreign.putInt(address, value); } public final void putLong(long address, long value) { Foreign.putLong(address, value); } public final void putFloat(long address, float value) { Foreign.putFloat(address, value); } public final void putDouble(long address, double value) { Foreign.putDouble(address, value); } public final void setMemory(long address, long size, byte value) { Foreign.setMemory(address, size, value); } public final void _copyMemory(long src, long dst, long size) { Foreign.copyMemory(src, dst, size); } public final void memcpy(long dst, long src, long size) { Foreign.memcpy(dst, src, size); } public final void memmove(long dst, long src, long size) { Foreign.memmove(dst, src, size); } public final long memchr(long address, int value, long size) { return Foreign.memchr(address, value, size); } public final void putByteArray(long address, byte[] data, int offset, int length) { Foreign.putByteArray(address, data, offset, length); } public final void getByteArray(long address, byte[] data, int offset, int length) { Foreign.getByteArray(address, data, offset, length); } public final void putCharArray(long address, char[] data, int offset, int length) { Foreign.putCharArray(address, data, offset, length); } public final void getCharArray(long address, char[] data, int offset, int length) { Foreign.getCharArray(address, data, offset, length); } public final void putShortArray(long address, short[] data, int offset, int length) { Foreign.putShortArray(address, data, offset, length); } public final void getShortArray(long address, short[] data, int offset, int length) { Foreign.getShortArray(address, data, offset, length); } public final void putIntArray(long address, int[] data, int offset, int length) { Foreign.putIntArray(address, data, offset, length); } public final void getIntArray(long address, int[] data, int offset, int length) { Foreign.getIntArray(address, data, offset, length); } public final void putLongArray(long address, long[] data, int offset, int length) { Foreign.putLongArray(address, data, offset, length); } public final void getLongArray(long address, long[] data, int offset, int length) { Foreign.getLongArray(address, data, offset, length); } public final void putFloatArray(long address, float[] data, int offset, int length) { Foreign.putFloatArray(address, data, offset, length); } public final void getFloatArray(long address, float[] data, int offset, int length) { Foreign.getFloatArray(address, data, offset, length); } public final void putDoubleArray(long address, double[] data, int offset, int length) { Foreign.putDoubleArray(address, data, offset, length); } public final void getDoubleArray(long address, double[] data, int offset, int length) { Foreign.getDoubleArray(address, data, offset, length); } public final long getStringLength(long address) { return Foreign.strlen(address); } public final byte[] getZeroTerminatedByteArray(long address) { return Foreign.getZeroTerminatedByteArray(address); } public final byte[] getZeroTerminatedByteArray(long address, int maxlen) { return Foreign.getZeroTerminatedByteArray(address, maxlen); } public final void putZeroTerminatedByteArray(long address, byte[] data, int offset, int length) { Foreign.putZeroTerminatedByteArray(address, data, offset, length); } } /** * A 32 bit optimized implementation of MemoryIO using JNI. */ private static final class NativeImpl32 extends NativeImpl { public final long getAddress(long address) { // Mask with ADDRESS_MASK to cancel out any sign extension return ((long) Foreign.getInt(address)) & ADDRESS_MASK; } public final void putAddress(long address, long value) { Foreign.putInt(address, (int) value); } } private static final class CheckedNativeImpl extends MemoryIO { public final byte getByte(long address) { return Foreign.getByteChecked(address); } public final short getShort(long address) { return Foreign.getShortChecked(address); } public final int getInt(long address) { return Foreign.getIntChecked(address); } public final long getLong(long address) { return Foreign.getLongChecked(address); } public final float getFloat(long address) { return Foreign.getFloatChecked(address); } public final double getDouble(long address) { return Foreign.getDoubleChecked(address); } public final void putByte(long address, byte value) { Foreign.putByteChecked(address, value); } public final void putShort(long address, short value) { Foreign.putShortChecked(address, value); } public final void putInt(long address, int value) { Foreign.putIntChecked(address, value); } public final void putLong(long address, long value) { Foreign.putLongChecked(address, value); } public final void putFloat(long address, float value) { Foreign.putFloatChecked(address, value); } public final void putDouble(long address, double value) { Foreign.putDoubleChecked(address, value); } public final void setMemory(long address, long size, byte value) { Foreign.setMemoryChecked(address, size, value); } public final void _copyMemory(long src, long dst, long size) { Foreign.copyMemoryChecked(src, dst, size); } public final long getAddress(long address) { return Foreign.getAddressChecked(address) & ADDRESS_MASK; } public final void putAddress(long address, long value) { Foreign.putAddressChecked(address, value); } public final void memcpy(long dst, long src, long size) { Foreign.memcpyChecked(dst, src, size); } public final void memmove(long dst, long src, long size) { Foreign.memmoveChecked(dst, src, size); } public final long memchr(long address, int value, long size) { return Foreign.memchrChecked(address, value, size); } public final void putByteArray(long address, byte[] data, int offset, int length) { Foreign.putByteArrayChecked(address, data, offset, length); } public final void getByteArray(long address, byte[] data, int offset, int length) { Foreign.getByteArrayChecked(address, data, offset, length); } public final void putCharArray(long address, char[] data, int offset, int length) { Foreign.putCharArrayChecked(address, data, offset, length); } public final void getCharArray(long address, char[] data, int offset, int length) { Foreign.getCharArrayChecked(address, data, offset, length); } public final void putShortArray(long address, short[] data, int offset, int length) { Foreign.putShortArrayChecked(address, data, offset, length); } public final void getShortArray(long address, short[] data, int offset, int length) { Foreign.getShortArrayChecked(address, data, offset, length); } public final void putIntArray(long address, int[] data, int offset, int length) { Foreign.putIntArrayChecked(address, data, offset, length); } public final void getIntArray(long address, int[] data, int offset, int length) { Foreign.getIntArrayChecked(address, data, offset, length); } public final void putLongArray(long address, long[] data, int offset, int length) { Foreign.putLongArrayChecked(address, data, offset, length); } public final void getLongArray(long address, long[] data, int offset, int length) { Foreign.getLongArrayChecked(address, data, offset, length); } public final void putFloatArray(long address, float[] data, int offset, int length) { Foreign.putFloatArrayChecked(address, data, offset, length); } public final void getFloatArray(long address, float[] data, int offset, int length) { Foreign.getFloatArrayChecked(address, data, offset, length); } public final void putDoubleArray(long address, double[] data, int offset, int length) { Foreign.putDoubleArrayChecked(address, data, offset, length); } public final void getDoubleArray(long address, double[] data, int offset, int length) { Foreign.getDoubleArrayChecked(address, data, offset, length); } public final long getStringLength(long address) { return Foreign.strlenChecked(address); } public final byte[] getZeroTerminatedByteArray(long address) { return Foreign.getZeroTerminatedByteArrayChecked(address); } public final byte[] getZeroTerminatedByteArray(long address, int maxlen) { return Foreign.getZeroTerminatedByteArrayChecked(address, maxlen); } public final void putZeroTerminatedByteArray(long address, byte[] data, int offset, int length) { Foreign.putZeroTerminatedByteArrayChecked(address, data, offset, length); } } /** * A 64 bit optimized implementation of MemoryIO using JNI. */ private static final class NativeImpl64 extends NativeImpl { public final long getAddress(long address) { return Foreign.getLong(address); } public final void putAddress(long address, long value) { Foreign.putLong(address, value); } } /** * An implementation of MemoryIO using sun.misc.Unsafe */ private static abstract class UnsafeImpl extends MemoryIO { protected static sun.misc.Unsafe unsafe = sun.misc.Unsafe.class.cast(getUnsafe()); private static Object getUnsafe() { try { Class sunUnsafe = Class.forName("sun.misc.Unsafe"); Field f = sunUnsafe.getDeclaredField("theUnsafe"); f.setAccessible(true); return f.get(sunUnsafe); } catch (Exception ex) { throw new RuntimeException(ex); } } public final byte getByte(long address) { return unsafe.getByte(address); } public final short getShort(long address) { return unsafe.getShort(address); } public final int getInt(long address) { return unsafe.getInt(address); } public final long getLong(long address) { return unsafe.getLong(address); } public final float getFloat(long address) { return unsafe.getFloat(address); } public final double getDouble(long address) { return unsafe.getDouble(address); } public final void putByte(long address, byte value) { unsafe.putByte(address, value); } public final void putShort(long address, short value) { unsafe.putShort(address, value); } public final void putInt(long address, int value) { unsafe.putInt(address, value); } public final void putLong(long address, long value) { unsafe.putLong(address, value); } public final void putFloat(long address, float value) { unsafe.putFloat(address, value); } public final void putDouble(long address, double value) { unsafe.putDouble(address, value); } public final void _copyMemory(long src, long dst, long size) { unsafe.copyMemory(src, dst, size); } public final void setMemory(long src, long size, byte value) { unsafe.setMemory(src, size, value); } public final void memcpy(long dst, long src, long size) { Foreign.memcpy(dst, src, size); } public final void memmove(long dst, long src, long size) { Foreign.memmove(dst, src, size); } public final long memchr(long address, int value, long size) { return Foreign.memchr(address, value, size); } public final void putByteArray(long address, byte[] data, int offset, int length) { Foreign.putByteArray(address, data, offset, length); } public final void getByteArray(long address, byte[] data, int offset, int length) { Foreign.getByteArray(address, data, offset, length); } public final void putCharArray(long address, char[] data, int offset, int length) { Foreign.putCharArray(address, data, offset, length); } public final void getCharArray(long address, char[] data, int offset, int length) { Foreign.getCharArray(address, data, offset, length); } public final void putShortArray(long address, short[] data, int offset, int length) { Foreign.putShortArray(address, data, offset, length); } public final void getShortArray(long address, short[] data, int offset, int length) { Foreign.getShortArray(address, data, offset, length); } public final void putIntArray(long address, int[] data, int offset, int length) { Foreign.putIntArray(address, data, offset, length); } public final void getIntArray(long address, int[] data, int offset, int length) { Foreign.getIntArray(address, data, offset, length); } public final void putLongArray(long address, long[] data, int offset, int length) { Foreign.putLongArray(address, data, offset, length); } public final void getLongArray(long address, long[] data, int offset, int length) { Foreign.getLongArray(address, data, offset, length); } public final void putFloatArray(long address, float[] data, int offset, int length) { Foreign.putFloatArray(address, data, offset, length); } public final void getFloatArray(long address, float[] data, int offset, int length) { Foreign.getFloatArray(address, data, offset, length); } public final void putDoubleArray(long address, double[] data, int offset, int length) { Foreign.putDoubleArray(address, data, offset, length); } public final void getDoubleArray(long address, double[] data, int offset, int length) { Foreign.getDoubleArray(address, data, offset, length); } public final long getStringLength(long address) { return Foreign.strlen(address); } public final byte[] getZeroTerminatedByteArray(long address) { return Foreign.getZeroTerminatedByteArray(address); } public final byte[] getZeroTerminatedByteArray(long address, int maxlen) { return Foreign.getZeroTerminatedByteArray(address, maxlen); } public final void putZeroTerminatedByteArray(long address, byte[] data, int offset, int length) { Foreign.putZeroTerminatedByteArray(address, data, offset, length); } } /** * A 32 bit optimized implementation of MemoryIO using sun.misc.Unsafe */ private static class UnsafeImpl32 extends UnsafeImpl { public final long getAddress(long address) { return ((long) unsafe.getInt(address)) & ADDRESS_MASK; } public final void putAddress(long address, long value) { unsafe.putInt(address, (int) value); } } /** * A 64 bit optimized implementation of MemoryIO using sun.misc.Unsafe */ private static class UnsafeImpl64 extends UnsafeImpl { public final long getAddress(long address) { return unsafe.getLong(address); } public final void putAddress(long address, long value) { unsafe.putLong(address, value); } } /** * Verifies that there is are accessor functions (get,put) for a particular * primitive type in the sun.misc.Unsafe class. * * @param unsafeClass The class of sun.misc.Unsafe * @param primitive The class of the primitive type. * @throws NoSuchMethodException If no accessors for that primitive type exist. */ @SuppressWarnings("unchecked") private static void verifyAccessor(Class unsafeClass, Class primitive) throws NoSuchMethodException { String primitiveName = primitive.getSimpleName(); String typeName = primitiveName.substring(0, 1).toUpperCase() + primitiveName.substring(1); Method get = unsafeClass.getDeclaredMethod("get" + typeName, new Class[] { long.class }); if (!get.getReturnType().equals(primitive)) { throw new NoSuchMethodException("Incorrect return type for " + get.getName()); } unsafeClass.getDeclaredMethod("put" + typeName, new Class[] { long.class, primitive}); } /** * Determines the best Unsafe implementation to use. Some platforms (e.g. gcj) * do not have all the methods that sun.misc.Unsafe does, so we need to check for them. * * This also handles the case where sun.misc.Unsafe vanishes from future versions * of the JVM. * @return true if sun.misc.Unsafe is available and usable */ @SuppressWarnings("unchecked") static boolean isUnsafeAvailable() { try { Class sunClass = Class.forName("sun.misc.Unsafe"); // // Verify that all the accessor methods we need are there // Class[] primitiveTypes = { byte.class, short.class, int.class, long.class, float.class, double.class }; for (Class type : primitiveTypes) { verifyAccessor(sunClass, type); } // // Check for any other methods we need // sunClass.getDeclaredMethod("getAddress", new Class[] { long.class }); sunClass.getDeclaredMethod("putAddress", new Class[] { long.class, long.class }); sunClass.getDeclaredMethod("allocateMemory", new Class[] { long.class }); sunClass.getDeclaredMethod("freeMemory", new Class[] { long.class }); return true; } catch (Throwable ex) { return false; } } } jffi-1.2.7/src/main/java/com/kenai/jffi/NativeMethod.java000066400000000000000000000035331247047424400231240ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Represents a native implementation of a method for a class */ public final class NativeMethod { final long function; final String name; final String signature; /** * Creates a new native method wrapper. * * @param address The address of the native method. * @param name The name of the java method. * @param signature The java signature. */ public NativeMethod(long address, String name, String signature) { this.function = address; this.name = name; this.signature = signature; } } jffi-1.2.7/src/main/java/com/kenai/jffi/NativeMethods.java000066400000000000000000000131641247047424400233100ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import java.util.logging.Level; import java.util.logging.Logger; /** * Utility class to register native methods on a class */ public final class NativeMethods { /** * Store a link from the class to the native method holder in a weak * hash map, so as long as the class remains alive, the native memory for the * structures remains alive. * * This doesn't seem to be necessary on sun's jvm, but best do it to be safe. */ private static final Map registeredMethods = new WeakHashMap(); private final ResourceHolder memory; private NativeMethods(ResourceHolder memory) { this.memory = memory; } /** * Registers the native methods for a class. * * @param clazz The java class to register the native methods for. * @param methods The list of methods to attach to the class. */ public static synchronized final void register(Class clazz, List methods) { // // Calculate how much memory is needed for the function names + signatures // int stringSize = 0; for (NativeMethod m : methods) { stringSize += m.name.getBytes().length + 1; stringSize += m.signature.getBytes().length + 1; } final int ptrSize = Platform.getPlatform().addressSize() / 8; final MemoryIO mm = MemoryIO.getInstance(); // // Each JNINativeMethod struct is 3 pointers // i.e. // typedef struct { // char *name; // char *signature; // void *fnPtr; // } JNINativeMethod; int structSize = methods.size() * 3 * ptrSize; long memory = mm.allocateMemory(structSize + stringSize, true); if (memory == 0L) { throw new OutOfMemoryError("could not allocate native memory"); } NativeMethods nm = new NativeMethods(new ResourceHolder(mm, memory)); int off = 0; int stringOff = structSize; for (NativeMethod m : methods) { byte[] name = m.name.getBytes(); long nameAddress = memory + stringOff; stringOff += name.length + 1; mm.putZeroTerminatedByteArray(nameAddress, name, 0, name.length); byte[] sig = m.signature.getBytes(); long sigAddress = memory + stringOff; stringOff += sig.length + 1; mm.putZeroTerminatedByteArray(sigAddress, sig, 0, sig.length); mm.putAddress(memory + off, nameAddress); off += ptrSize; mm.putAddress(memory + off, sigAddress); off += ptrSize; mm.putAddress(memory + off, m.function); off += ptrSize; } if (Foreign.getInstance().registerNatives(clazz, memory, methods.size()) != Foreign.JNI_OK) { throw new RuntimeException("failed to register native methods"); } registeredMethods.put(clazz, nm); } /** * Removes all native method attachments for the specified class. * * @param clazz The class to unregister the native methods on. */ public static synchronized final void unregister(Class clazz) { if (!registeredMethods.containsKey(clazz)) { throw new IllegalArgumentException("methods were not registered on class via NativeMethods.register"); } if (Foreign.getInstance().unregisterNatives(clazz) != Foreign.JNI_OK) { throw new RuntimeException("failed to unregister native methods"); } registeredMethods.remove(clazz); } private static final class ResourceHolder { private final MemoryIO mm; private final long memory; public ResourceHolder(MemoryIO mm, long memory) { this.mm = mm; this.memory = memory; } @Override protected void finalize() throws Throwable { try { mm.freeMemory(memory); } catch (Throwable t) { Logger.getLogger(getClass().getName()).log(Level.WARNING, "Exception when freeing native method struct array: %s", t.getLocalizedMessage()); } finally { super.finalize(); } } } } jffi-1.2.7/src/main/java/com/kenai/jffi/NativeObjectParameterInvoker.java000066400000000000000000000303641247047424400263130ustar00rootroot00000000000000 package com.kenai.jffi; /** * */ final class NativeObjectParameterInvoker extends ObjectParameterInvoker { private final Foreign foreign; public final boolean isNative() { return true; } NativeObjectParameterInvoker(Foreign foreign) { this.foreign = foreign; } public final long invokeN1O1rN(Function function, long n1, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return foreign.invokeN1O1(function.getContextAddress(), function.getFunctionAddress(), n1, o1, o1flags.asObjectInfo(), o1off, o1len); } public final long invokeN1O1(CallContext ctx, long fn, long n1, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return foreign.invokeN1O1(ctx.getAddress(), fn, n1, o1, o1flags.asObjectInfo(), o1off, o1len); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 first numeric argument. * @param n2 The second numeric argument. * @param o1 array or buffer, to be passed as a pointer for the first numeric parameter. * @param o1off offset from the start of the array or buffer. * @param o1len length of the array to use. * @param o1flags object flags (type, direction, parameter index). */ public final long invokeN2O1rN(Function function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return foreign.invokeN2O1(function.getContextAddress(), function.getFunctionAddress(), n1, n2, o1, o1flags.asObjectInfo(), o1off, o1len); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 first numeric argument. * @param n2 The second numeric argument. * @param o1 array or buffer, to be passed as a pointer for the first numeric parameter. * @param o1off offset from the start of the array or buffer. * @param o1len length of the array to use. * @param o1flags object flags (type, direction, parameter index). */ public final long invokeN2O1(CallContext ctx, long function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return foreign.invokeN2O1(ctx.getAddress(), function, n1, n2, o1, o1flags.asObjectInfo(), o1off, o1len); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 The first numeric argument. * @param n2 The second numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1off The offset from the start of the array or buffer. * @param o1len The length of the array to use. * @param o1flags Object flags (direction, type, parameter index). * @param o2 An Object (array or buffer), to be passed as a pointer. * @param o2off The offset from the start of the array or buffer. * @param o2len The length of the array to use. * @param o2flags Object flags (direction, type, idx). */ public final long invokeN2O2rN(Function function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return foreign.invokeN2O2(function.getContextAddress(), function.getFunctionAddress(), n1, n2, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 The first numeric argument. * @param n2 The second numeric argument. * @param n3 The third numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1off The offset from the start of the array or buffer. * @param o1len The length of the array to use. * @param o1flags Object flags (direction, type, parameter index). */ public final long invokeN3O1rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return foreign.invokeN3O1(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, o1, o1flags.asObjectInfo(), o1off, o1len); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 The first numeric argument. * @param n2 The second numeric argument. * @param n3 The third numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1off The offset from the start of the array or buffer. * @param o1len The length of the array to use. * @param o1flags Object flags (direction, type, parameter index). * @param o2 An Object (array or buffer), to be passed as a pointer. * @param o2off The offset from the start of the array or buffer. * @param o2len The length of the array to use. * @param o2flags Object flags (direction, type, idx). */ public final long invokeN3O2rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return foreign.invokeN3O2(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len); } public final long invokeN3O3rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { return foreign.invokeN3O3(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len, o3, o3flags.asObjectInfo(), o3off, o3len); } public final long invokeN4O1rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return foreign.invokeN4O1(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, o1, o1flags.asObjectInfo(), o1off, o1len); } public final long invokeN4O2rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return foreign.invokeN4O2(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len); } public final long invokeN4O3rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { return foreign.invokeN4O3(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len, o3, o3flags.asObjectInfo(), o3off, o3len); } @Override public long invokeN5O1rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return foreign.invokeN5O1(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, n5, o1, o1flags.asObjectInfo(), o1off, o1len); } @Override public long invokeN5O2rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return foreign.invokeN5O2(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, n5, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len); } public final long invokeN5O3rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { return foreign.invokeN5O3(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, n5, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len, o3, o3flags.asObjectInfo(), o3off, o3len); } @Override public long invokeN6O1rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags) { return foreign.invokeN6O1(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, n5, n6, o1, o1flags.asObjectInfo(), o1off, o1len); } @Override public long invokeN6O2rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags) { return foreign.invokeN6O2(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, n5, n6, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len); } public final long invokeN6O3rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags) { return foreign.invokeN6O3(function.getContextAddress(), function.getFunctionAddress(), n1, n2, n3, n4, n5, n6, o1, o1flags.asObjectInfo(), o1off, o1len, o2, o2flags.asObjectInfo(), o2off, o2len, o3, o3flags.asObjectInfo(), o3off, o3len); } } jffi-1.2.7/src/main/java/com/kenai/jffi/NativeType.java000066400000000000000000000041601247047424400226220ustar00rootroot00000000000000/* * Copyright (C) 2008-2010 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * */ public enum NativeType { VOID(Foreign.TYPE_VOID), FLOAT(Foreign.TYPE_FLOAT), DOUBLE(Foreign.TYPE_DOUBLE), LONGDOUBLE(Foreign.TYPE_LONGDOUBLE), UINT8(Foreign.TYPE_UINT8), SINT8(Foreign.TYPE_SINT8), UINT16(Foreign.TYPE_UINT16), SINT16(Foreign.TYPE_SINT16), UINT32(Foreign.TYPE_UINT32), SINT32(Foreign.TYPE_SINT32), UINT64(Foreign.TYPE_UINT64), SINT64(Foreign.TYPE_SINT64), POINTER(Foreign.TYPE_POINTER), UCHAR(Foreign.TYPE_UCHAR), SCHAR(Foreign.TYPE_SCHAR), USHORT(Foreign.TYPE_USHORT), SSHORT(Foreign.TYPE_SSHORT), UINT(Foreign.TYPE_UINT), SINT(Foreign.TYPE_SINT), ULONG(Foreign.TYPE_ULONG), SLONG(Foreign.TYPE_SLONG), STRUCT(Foreign.TYPE_STRUCT); final int ffiType; NativeType(int ffiType) { this.ffiType = ffiType; } } jffi-1.2.7/src/main/java/com/kenai/jffi/ObjectBuffer.java000066400000000000000000000254051247047424400230770ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Holds objects the native code must handle - such as primitive arrays */ final class ObjectBuffer { /** Copy the array contents to native memory before calling the function */ public static final int IN = 0x1; /** After calling the function, reload the array contents from native memory */ public static final int OUT = 0x2; /** Append a NUL byte to the array contents after copying to native memory */ public static final int ZERO_TERMINATE = 0x4; /** Pin the array memory and pass the JVM memory pointer directly to the function */ public static final int PINNED = 0x8; /** For OUT arrays, clear the temporary native memory area */ public static final int CLEAR = 0x10; /* * WARNING: The following flags cannot be altered without recompiling the native code */ static final int INDEX_SHIFT = 16; static final int INDEX_MASK = 0x00ff0000; static final int TYPE_SHIFT = 24; static final int TYPE_MASK = 0xff << TYPE_SHIFT; static final int PRIM_MASK = 0x0f << TYPE_SHIFT; static final int FLAGS_SHIFT = 0; static final int FLAGS_MASK = 0xff; static final int ARRAY = 0x10 << TYPE_SHIFT; static final int BUFFER = 0x20 << TYPE_SHIFT; static final int JNI = 0x40 << TYPE_SHIFT; static final int BYTE = 0x1 << TYPE_SHIFT; static final int SHORT = 0x2 << TYPE_SHIFT; static final int INT = 0x3 << TYPE_SHIFT; static final int LONG = 0x4 << TYPE_SHIFT; static final int FLOAT = 0x5 << TYPE_SHIFT; static final int DOUBLE = 0x6 << TYPE_SHIFT; static final int BOOLEAN = 0x7 << TYPE_SHIFT; static final int CHAR = 0x8 << TYPE_SHIFT; /* NOTE: The JNI types can overlap the primitive type, since they are mutually exclusive */ /** The JNIEnv address */ public static final int JNIENV = 0x1 << TYPE_SHIFT; /** The jobject handle */ public static final int JNIOBJECT = 0x2 << TYPE_SHIFT; /** The objects stored in this buffer */ private Object[] objects; /** * The flags/offset/length descriptor array. * * Along with each object, a 3-tuple is stored in the descriptor array. * * The first element of the tuple stores a mask of the type, parameter index and array flags * The second element stores the offset within the array the data starts. * The third element stores the length of data. */ private int[] info; /** The index of the next descriptor storage slot */ private int infoIndex = 0; /** The index of the next object storage slot */ private int objectIndex = 0; ObjectBuffer() { objects = new Object[1]; info = new int[objects.length * 3]; } ObjectBuffer(int objectCount) { objects = new Object[objectCount]; info = new int[objectCount * 3]; } /** * Gets the number of objects stored in this ObjectBuffer. * * @return the number of objects already stored. */ final int objectCount() { return objectIndex; } /** * Gets the object descriptor array. * * @return An array of integers describing the objects stored. */ final int[] info() { return info; } /** * Gets the array of stored objects. * * @return An array of objects stored in this buffer. */ final Object[] objects() { return objects; } /** Ensures that sufficient space is available to insert at least one more object */ private final void ensureSpace() { if (objects.length <= (objectIndex + 1)) { Object[] newObjects = new Object[objects.length << 1]; System.arraycopy(objects, 0, newObjects, 0, objectIndex); objects = newObjects; int[] newInfo = new int[objects.length * 3]; System.arraycopy(info, 0, newInfo, 0, objectIndex * 3); info = newInfo; } } /** * Encodes the native object flags for an array. * * @param ioflags The array flags (IN, OUT) for the object. * @param type The type of the object. * @param index The parameter index the object should be passed as. * @return A bitmask of flags. */ static final int makeObjectFlags(int ioflags, int type, int index) { return (ioflags & FLAGS_MASK) | ((index << INDEX_SHIFT) & INDEX_MASK) | type; } /** * Encodes the native object flags for an NIO Buffer. * * @param index The parameter index of the buffer. * @return A bitmask of flags. */ static final int makeBufferFlags(int index) { return ((index << INDEX_SHIFT) & INDEX_MASK) | BUFFER; } private static final int makeJNIFlags(int index, int type) { return ((index << INDEX_SHIFT) & INDEX_MASK) | JNI | type; } /** * Adds a java byte array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT, NULTERMINATE) */ public void putArray(int index, byte[] array, int offset, int length, int flags) { putObject(array, offset, length, makeObjectFlags(flags, BYTE | ARRAY, index)); } /** * Adds a java short array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, short[] array, int offset, int length, int flags) { putObject(array, offset, length, makeObjectFlags(flags, SHORT | ARRAY, index)); } /** * Adds a java int array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, int[] array, int offset, int length, int flags) { putObject(array, offset, length, makeObjectFlags(flags, INT | ARRAY, index)); } /** * Adds a java long array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, long[] array, int offset, int length, int flags) { putObject(array, offset, length, makeObjectFlags(flags, LONG | ARRAY, index)); } /** * Adds a java float array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, float[] array, int offset, int length, int flags) { putObject(array, offset, length, makeObjectFlags(flags, FLOAT | ARRAY, index)); } /** * Adds a java double array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, double[] array, int offset, int length, int flags) { putObject(array, offset, length, makeObjectFlags(flags, DOUBLE | ARRAY, index)); } /** * Adds a java boolean array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, boolean[] array, int offset, int length, int flags) { putObject(array, offset, length, makeObjectFlags(flags, BOOLEAN | ARRAY, index)); } /** * Adds a java char array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, char[] array, int offset, int length, int flags) { putObject(array, offset, length, makeObjectFlags(flags, CHAR | ARRAY, index)); } /** * Adds a java direct buffer as a pointer parameter. * @param buffer The buffer to use as a pointer argument. * @param offset An offset to add to the buffer native address. * @param length The length of the buffer to use. */ public void putDirectBuffer(int index, java.nio.Buffer obj, int offset, int length) { putObject(obj, offset, length, makeBufferFlags(index)); } /** * Put the address of the current JNIEnv into this parameter position * * @param index The index of the parameter. */ public void putJNI(int index, Object obj, int type) { putObject(obj, 0, 0, makeJNIFlags(index, type)); } void putObject(Object array, int offset, int length, int flags) { ensureSpace(); objects[objectIndex++] = array; info[infoIndex++] = flags; info[infoIndex++] = offset; info[infoIndex++] = length; } } jffi-1.2.7/src/main/java/com/kenai/jffi/ObjectParameterInfo.java000066400000000000000000000077221247047424400244240ustar00rootroot00000000000000package com.kenai.jffi; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public final class ObjectParameterInfo { private static final ConcurrentMap CACHE = new ConcurrentHashMap(); private final int parameterIndex; private final int ioflags; private final int objectInfo; public static ObjectParameterInfo create(int parameterIndex, ObjectType objectType, ComponentType componentType, int ioflags) { return getCachedInfo(ObjectBuffer.makeObjectFlags(ioflags, objectType.value | componentType.value, parameterIndex)); } public static ObjectParameterInfo create(int parameterIndex, int ioflags) { return getCachedInfo(ObjectBuffer.makeObjectFlags(ioflags, 0, parameterIndex)); } private static ObjectParameterInfo getCachedInfo(int objectInfo) { ObjectParameterInfo info = CACHE.get(objectInfo); if (info != null) { return info; } ObjectParameterInfo cachedInfo = CACHE.putIfAbsent(objectInfo, info = new ObjectParameterInfo(objectInfo)); return cachedInfo != null ? cachedInfo : info; } private ObjectParameterInfo(int objectInfo) { this.objectInfo = objectInfo; this.ioflags = objectInfo & ObjectBuffer.FLAGS_MASK; this.parameterIndex = (objectInfo & ObjectBuffer.INDEX_MASK) >> ObjectBuffer.INDEX_SHIFT; } /** Copy the array contents to native memory before calling the function */ public static final int IN = ObjectBuffer.IN; /** After calling the function, reload the array contents from native memory */ public static final int OUT = ObjectBuffer.OUT; /** Pin the array memory and pass the JVM memory pointer directly to the function */ public static final int PINNED = ObjectBuffer.PINNED; /** Append a NUL byte to the array contents after copying to native memory */ public static final int NULTERMINATE = ObjectBuffer.ZERO_TERMINATE; /** For OUT arrays, clear the native memory area before passing to the native function */ public static final int CLEAR = ObjectBuffer.CLEAR; public static final ObjectType ARRAY = ObjectType.ARRAY; public static final ObjectType BUFFER = ObjectType.BUFFER; public static enum ObjectType { ARRAY(ObjectBuffer.ARRAY), BUFFER(ObjectBuffer.BUFFER); final int value; ObjectType(int type) { this.value = type; } } public static enum ComponentType { BYTE(ObjectBuffer.BYTE), SHORT(ObjectBuffer.SHORT), INT(ObjectBuffer.INT), LONG(ObjectBuffer.LONG), FLOAT(ObjectBuffer.FLOAT), DOUBLE(ObjectBuffer.DOUBLE), BOOLEAN(ObjectBuffer.BOOLEAN), CHAR(ObjectBuffer.CHAR); final int value; ComponentType(int type) { this.value = type; } } public static final ComponentType BYTE = ComponentType.BYTE; public static final ComponentType SHORT = ComponentType.SHORT; public static final ComponentType INT = ComponentType.INT; public static final ComponentType LONG = ComponentType.LONG; public static final ComponentType FLOAT = ComponentType.FLOAT; public static final ComponentType DOUBLE = ComponentType.DOUBLE; public static final ComponentType BOOLEAN = ComponentType.BOOLEAN; public static final ComponentType CHAR = ComponentType.CHAR; final int asObjectInfo() { return objectInfo; } final int ioflags() { return ioflags; } public final int getParameterIndex() { return parameterIndex; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ObjectParameterInfo info = (ObjectParameterInfo) o; return objectInfo == info.objectInfo; } @Override public int hashCode() { return 31 * objectInfo; } } jffi-1.2.7/src/main/java/com/kenai/jffi/ObjectParameterInvoker.java000066400000000000000000000173361247047424400251500ustar00rootroot00000000000000package com.kenai.jffi; abstract public class ObjectParameterInvoker { private static final class SingletonHolder { static final ObjectParameterInvoker INSTANCE = Foreign.getInstance().getVersion() >= 0x01000A /* version 1.0.10 */ ? newNativeInvoker() : newHeapInvoker(); } public static ObjectParameterInvoker getInstance() { return SingletonHolder.INSTANCE; } static ObjectParameterInvoker newNativeInvoker() { return new NativeObjectParameterInvoker(Foreign.getInstance()); } static ObjectParameterInvoker newHeapInvoker() { return new HeapObjectParameterInvoker(Foreign.getInstance()); } abstract public boolean isNative(); /** * Invokes a function with one numeric argument (which may be a pointer), and returns a numeric value. * * @param function The Function to invoke. * @param n1 numeric argument. * @param o1 array or buffer, to be passed as a pointer for the first numeric parameter. * @param o1off offset from the start of the array or buffer. * @param o1len length of the array to use. * @param o1flags object flags (type, direction, parameter index). */ abstract public long invokeN1O1rN(Function function, long n1, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags); /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 first numeric argument. * @param n2 The second numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1off offset from the start of the array or buffer. * @param o1len length of the array to use. * @param o1flags object flags (type, direction, parameter index). */ abstract public long invokeN2O1rN(Function function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags); /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 first numeric argument. * @param n2 The second numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1off offset from the start of the array or buffer. * @param o1len length of the array to use. * @param o1flags object flags (type, direction, parameter index). * @param o2 An Object (array or buffer), to be passed as a pointer. * @param o2off The offset from the start of the array or buffer. * @param o2len The length of the array to use. * @param o2flags Object flags (direction, type, idx). */ abstract public long invokeN2O2rN(Function function, long n1, long n2, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags); /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param n1 first numeric argument. * @param n2 The second numeric argument. * @param n3 The second numeric argument. * @param o1 An Object (array or buffer), to be passed as a pointer. * @param o1off offset from the start of the array or buffer. * @param o1len length of the array to use. * @param o1flags object flags (type, direction, parameter index). */ abstract public long invokeN3O1rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags); abstract public long invokeN3O2rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags); abstract public long invokeN3O3rN(Function function, long n1, long n2, long n3, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags); abstract public long invokeN4O1rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags); abstract public long invokeN4O2rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags); abstract public long invokeN4O3rN(Function function, long n1, long n2, long n3, long n4, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags); abstract public long invokeN5O1rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags); abstract public long invokeN5O2rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags); abstract public long invokeN5O3rN(Function function, long n1, long n2, long n3, long n4, long n5, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags); abstract public long invokeN6O1rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags); abstract public long invokeN6O2rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags); abstract public long invokeN6O3rN(Function function, long n1, long n2, long n3, long n4, long n5, long n6, Object o1, int o1off, int o1len, ObjectParameterInfo o1flags, Object o2, int o2off, int o2len, ObjectParameterInfo o2flags, Object o3, int o3off, int o3len, ObjectParameterInfo o3flags); } jffi-1.2.7/src/main/java/com/kenai/jffi/ObjectParameterStrategy.java000066400000000000000000000054061247047424400253300ustar00rootroot00000000000000/* * Copyright (C) 2011 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * */ abstract public class ObjectParameterStrategy { private final boolean isDirect; final int typeInfo; protected static enum StrategyType { DIRECT, HEAP } protected static final StrategyType DIRECT = StrategyType.DIRECT; protected static final StrategyType HEAP = StrategyType.HEAP; public ObjectParameterStrategy(boolean isDirect) { this(isDirect, ObjectParameterType.INVALID); } public ObjectParameterStrategy(boolean isDirect, ObjectParameterType type) { this.isDirect = isDirect; this.typeInfo = type.typeInfo; } public ObjectParameterStrategy(StrategyType type) { this(type, ObjectParameterType.INVALID); } public ObjectParameterStrategy(StrategyType strategyType, ObjectParameterType parameterType) { this.isDirect = strategyType == DIRECT; this.typeInfo = parameterType.typeInfo; } public final boolean isDirect() { return isDirect; } final int objectInfo(ObjectParameterInfo info) { int objectInfo = info.asObjectInfo(); // Over-ride the type info contained in the parameter info if (typeInfo != 0) { return (objectInfo & ~ObjectBuffer.TYPE_MASK) | typeInfo; } else { return objectInfo; } } abstract public long address(Object parameter); abstract public Object object(Object parameter); abstract public int offset(Object parameter); abstract public int length(Object parameter); } jffi-1.2.7/src/main/java/com/kenai/jffi/ObjectParameterType.java000066400000000000000000000064131247047424400244460ustar00rootroot00000000000000package com.kenai.jffi; import java.util.EnumSet; /** * Describes the type of an object parameter (e.g. byte array, byte buffer) */ public final class ObjectParameterType { final int typeInfo; public static ObjectParameterType create(ObjectType objectType, ComponentType componentType) { if (objectType == ObjectType.ARRAY) { return TypeCache.arrayTypeCache[componentType.ordinal()]; } else if (objectType == ObjectType.BUFFER) { return TypeCache.bufferTypeCache[componentType.ordinal()]; } return new ObjectParameterType(objectType.value | componentType.value); } ObjectParameterType(int typeInfo) { this.typeInfo = typeInfo; } ObjectParameterType(ObjectType objectType, ComponentType componentType) { this.typeInfo = objectType.value | componentType.value; } private static final class TypeCache { static final ObjectParameterType[] arrayTypeCache; static final ObjectParameterType[] bufferTypeCache; static { EnumSet componentTypes = EnumSet.allOf(ComponentType.class); arrayTypeCache = new ObjectParameterType[componentTypes.size()]; bufferTypeCache = new ObjectParameterType[componentTypes.size()]; for (ComponentType componentType : componentTypes) { arrayTypeCache[componentType.ordinal()] = new ObjectParameterType(ARRAY, componentType); bufferTypeCache[componentType.ordinal()] = new ObjectParameterType(BUFFER, componentType); } } } static final ObjectParameterType INVALID = new ObjectParameterType(0); static final ObjectParameterType NONE = new ObjectParameterType(0); public static enum ObjectType { ARRAY(ObjectBuffer.ARRAY), BUFFER(ObjectBuffer.BUFFER); final int value; ObjectType(int type) { this.value = type; } } public static final ObjectType ARRAY = ObjectType.ARRAY; public static final ObjectType BUFFER = ObjectType.BUFFER; public static enum ComponentType { BYTE(ObjectBuffer.BYTE), SHORT(ObjectBuffer.SHORT), INT(ObjectBuffer.INT), LONG(ObjectBuffer.LONG), FLOAT(ObjectBuffer.FLOAT), DOUBLE(ObjectBuffer.DOUBLE), BOOLEAN(ObjectBuffer.BOOLEAN), CHAR(ObjectBuffer.CHAR); final int value; ComponentType(int type) { this.value = type; } } public static final ComponentType BYTE = ComponentType.BYTE; public static final ComponentType SHORT = ComponentType.SHORT; public static final ComponentType INT = ComponentType.INT; public static final ComponentType LONG = ComponentType.LONG; public static final ComponentType FLOAT = ComponentType.FLOAT; public static final ComponentType DOUBLE = ComponentType.DOUBLE; public static final ComponentType BOOLEAN = ComponentType.BOOLEAN; public static final ComponentType CHAR = ComponentType.CHAR; @Override public boolean equals(Object o) { return this == o || (o instanceof ObjectParameterType && typeInfo == ((ObjectParameterType) o).typeInfo); } @Override public int hashCode() { return typeInfo; } } jffi-1.2.7/src/main/java/com/kenai/jffi/PageManager.java000066400000000000000000000131721247047424400227040ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Manages allocation, disposal and protection of native memory pages */ abstract public class PageManager { /** The memory should be executable */ public static final int PROT_EXEC = Foreign.PROT_EXEC; /** The memory should be readable */ public static final int PROT_READ = Foreign.PROT_READ; /** The memory should be writable */ public static final int PROT_WRITE = Foreign.PROT_WRITE; @SuppressWarnings("UnusedDeclaration") // loads the native lib private final Foreign foreign = Foreign.getInstance(); private int pageSize; private static final class SingletonHolder { public static final PageManager INSTANCE = Platform.getPlatform().getOS() == Platform.OS.WINDOWS ? new Windows() : new Unix(); } /** * Gets the page manager for the current platform. * * @return An instance of PageManager */ public static PageManager getInstance() { return SingletonHolder.INSTANCE; } /** * Gets the system page size. * * @return The size of a page on the current system, in bytes. */ public final long pageSize() { return pageSize != 0 ? pageSize : calculatePageSize(); } private long calculatePageSize() { long pgSize = Foreign.pageSize(); return pgSize < Integer.MAX_VALUE ? this.pageSize = (int) pgSize : pgSize; } /** * Allocates native memory pages. * * The memory allocated is aligned on a page boundary, and the size of the * allocated memory is npages * {@link #pageSize}. * * @param npages The number of pages to allocate. * @param protection The initial protection for the page. This must be a * bitmask of {@link #PROT_READ}, {@link #PROT_WRITE} and {@link #PROT_EXEC}. * * @return The native address of the allocated memory. */ public abstract long allocatePages(int npages, int protection); /** * Free pages allocated via {@link #allocatePages } * * @param address The memory address as returned from {@link #allocatePages} * @param npages The number of pages to free. */ public abstract void freePages(long address, int npages); /** * Sets the protection mask on a memory region. * * @param address The start of the memory region. * @param npages The number of pages to protect. * @param protection The protection mask. */ public abstract void protectPages(long address, int npages, int protection); static final class Unix extends PageManager { @Override public long allocatePages(int npages, int protection) { long sz = npages * pageSize(); long memory = Foreign.mmap(0, sz, protection, Foreign.MAP_ANON | Foreign.MAP_PRIVATE, -1, 0); return memory != -1L ? memory : 0L; } @Override public void freePages(long address, int npages) { Foreign.munmap(address, npages * pageSize()); } @Override public void protectPages(long address, int npages, int protection) { Foreign.mprotect(address, npages * pageSize(), protection); } } static final class Windows extends PageManager { public Windows() { } @Override public long allocatePages(int pageCount, int protection) { return Foreign.VirtualAlloc(0, (int) pageSize() * pageCount, Foreign.MEM_COMMIT | Foreign.MEM_RESERVE, w32prot(protection)); } @Override public void freePages(long address, int pageCount) { Foreign.VirtualFree(address, (int) pageSize() * pageCount, Foreign.MEM_RELEASE); } @Override public void protectPages(long address, int pageCount, int protection) { Foreign.VirtualProtect(address, (int) pageSize() * pageCount, w32prot(protection)); } private static int w32prot(int p) { int w32 = Foreign.PAGE_NOACCESS; if ((p & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) { w32 = Foreign.PAGE_READWRITE; } else if ((p & PROT_READ) == PROT_READ) { w32 = Foreign.PAGE_READONLY; } if ((p & PROT_EXEC) == PROT_EXEC) { w32 <<= 4; } return w32; } } } jffi-1.2.7/src/main/java/com/kenai/jffi/Platform.java000066400000000000000000000312501247047424400223160ustar00rootroot00000000000000/* * Copyright (C) 2007, 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; /** * Convenience class to interrogate the system about various platform-specific details. */ public abstract class Platform { private static final java.util.Locale LOCALE = java.util.Locale.ENGLISH; private final OS os; private final int javaVersionMajor; /** * The common names of operating systems. * * Note The names of the enum values are used in other parts of the * code to determine where to find the native stub library. Do not rename. */ public enum OS { /** MacOSX */ DARWIN, /** FreeBSD */ FREEBSD, /** NetBSD */ NETBSD, /** OpenBSD */ OPENBSD, /** Linux */ LINUX, /** Solaris (and OpenSolaris) */ SOLARIS, /** The evil borg operating system */ WINDOWS, /** IBM AIX */ AIX, /** IBM zOS **/ ZLINUX, /** No idea what the operating system is */ UNKNOWN; @Override public String toString() { return name().toLowerCase(LOCALE); } } /** * The common names of cpu architectures. * * Note The names of the enum values are used in other parts of the * code to determine where to find the native stub library. Do not rename. */ public enum CPU { /** Intel ia32 */ I386(32), /** AMD 64 bit (aka EM64T/X64) */ X86_64(64), /** Power PC 32 bit */ PPC(32), /** Power PC 64 bit */ PPC64(64), /** Sun sparc 32 bit */ SPARC(32), /** Sun sparc 64 bit */ SPARCV9(64), /** IBM zSeries S/390 64 bit */ S390X(64), /** ARM */ ARM(32), /** Unknown CPU */ UNKNOWN(64); CPU(int dataModel) { this.dataModel = dataModel; this.addressMask = dataModel == 32 ? 0xffffffffL : 0xffffffffffffffffL; } public final int dataModel; public final long addressMask; @Override public String toString() { return name().toLowerCase(LOCALE); } } /** * Holds a single, lazily loaded instance of Platform */ private static final class SingletonHolder { static final Platform PLATFORM = determinePlatform(determineOS()); } /** * Determines the operating system jffi is running on * * @return An member of the OS enum. */ private static final OS determineOS() { String osName = System.getProperty("os.name").split(" ")[0]; if (startsWithIgnoreCase(osName, "mac") || startsWithIgnoreCase(osName, "darwin")) { return OS.DARWIN; } else if (startsWithIgnoreCase(osName, "linux")) { return OS.LINUX; } else if (startsWithIgnoreCase(osName, "sunos") || startsWithIgnoreCase(osName, "solaris")) { return OS.SOLARIS; } else if (startsWithIgnoreCase(osName, "aix")) { return OS.AIX; } else if (startsWithIgnoreCase(osName, "openbsd")) { return OS.OPENBSD; } else if (startsWithIgnoreCase(osName, "freebsd")) { return OS.FREEBSD; } else if (startsWithIgnoreCase(osName, "windows")) { return OS.WINDOWS; } else { return OS.UNKNOWN; } } /** * Determines the Platform that best describes the OS * * @param os The operating system. * @return An instance of Platform */ private static final Platform determinePlatform(OS os) { switch (os) { case DARWIN: return newDarwinPlatform(); case WINDOWS: return newWindowsPlatform(); default: return newDefaultPlatform(os); } } private static Platform newDarwinPlatform() { return new Darwin(); } private static Platform newWindowsPlatform() { return new Windows(); } private static Platform newDefaultPlatform(OS os) { return new Default(os); } private static final class ArchHolder { public static final CPU cpu = determineCPU(); /** * Determines the CPU architecture the JVM is running on. * * This normalizes all the variations that are equivalent (e.g. i386, x86, i86pc) * into a common cpu type. * * @return A member of the CPU enum. */ private static CPU determineCPU() { String archString = null; try { archString = Foreign.getInstance().getArch(); } catch (UnsatisfiedLinkError ex) {} if (archString == null || "unknown".equals(archString)) { archString = System.getProperty("os.arch", "unknown"); } if ("x86".equalsIgnoreCase(archString) || "i386".equalsIgnoreCase(archString) || "i86pc".equalsIgnoreCase(archString)) { return CPU.I386; } else if ("x86_64".equalsIgnoreCase(archString) || "amd64".equalsIgnoreCase(archString)) { return CPU.X86_64; } else if ("ppc".equalsIgnoreCase(archString) || "powerpc".equalsIgnoreCase(archString)) { return CPU.PPC; } else if ("ppc64".equalsIgnoreCase(archString) || "powerpc64".equalsIgnoreCase(archString)) { return CPU.PPC64; } else if ("s390".equalsIgnoreCase(archString) || "s390x".equalsIgnoreCase(archString)) { return CPU.S390X; } else if ("arm".equalsIgnoreCase(archString)) { return CPU.ARM; } // Try to find by lookup up in the CPU list for (CPU cpu : CPU.values()) { if (cpu.name().equalsIgnoreCase(archString)) { return cpu; } } return CPU.UNKNOWN; } } /** * Constructs a new Platform instance. * * @param os The current operating system. */ private Platform(OS os) { this.os = os; int version = 5; try { String versionString = System.getProperty("java.version"); if (versionString != null) { String[] v = versionString.split("\\."); version = Integer.valueOf(v[1]); } } catch (Exception ex) { // Assume version 5 or above. version = 5; } javaVersionMajor = version; } /** * Gets the current Platform * * @return The current platform. */ public static final Platform getPlatform() { return SingletonHolder.PLATFORM; } /** * Gets the current Operating System. * * @return A OS value representing the current Operating System. */ public final OS getOS() { return os; } /** * Gets the current processor architecture the JVM is running on. * * @return A CPU value representing the current processor architecture. */ public final CPU getCPU() { return ArchHolder.cpu; } /** * Gets the version of the Java Virtual Machine (JVM) jffi is running on. * * @return A number representing the java version. e.g. 5 for java 1.5, 6 for java 1.6 */ public final int getJavaMajorVersion() { return javaVersionMajor; } /** * Gets the size of a C 'long' on the native platform. * * @return the size of a long in bits */ public abstract int longSize(); /** * Gets the size of a C address/pointer on the native platform. * * @return the size of a pointer in bits */ public final int addressSize() { return getCPU().dataModel; } /** * Gets the 32/64bit mask of a C address/pointer on the native platform. * * @return the size of a pointer in bits */ public final long addressMask() { return getCPU().addressMask; } /** * Gets the name of this Platform. * * @return The name of this platform. */ public String getName() { String osName = System.getProperty("os.name").split(" ")[0]; return getCPU().name().toLowerCase(LOCALE) + "-" + osName; } /** * Maps from a generic library name (e.g. "c") to the platform specific library name. * * @param libName The library name to map * @return The mapped library name. */ public String mapLibraryName(String libName) { // // A specific version was requested - use as is for search // if (libName.matches(getLibraryNamePattern())) { return libName; } return System.mapLibraryName(libName); } /** * Gets the regex string used to match platform-specific libraries * @return */ public String getLibraryNamePattern() { return "lib.*\\.so.*$"; } /** * Checks if the current platform is supported by JFFI. * * @return true if the platform is supported, else false. */ public boolean isSupported() { // // Call a function in the stub library - this will throw an // exception if there is no stub lib for this platform. // int version = Foreign.getInstance().getVersion(); if ((version & 0xffff00) == (Foreign.VERSION_MAJOR << 16 | Foreign.VERSION_MINOR << 8)) { return true; } throw new UnsatisfiedLinkError("Incorrect native library version"); } private static final class Default extends Platform { public Default(OS os) { super(os); } public final int longSize() { return getCPU().dataModel; } } /** * A {@link Platform} subclass representing the MacOS system. */ private static final class Darwin extends Platform { public Darwin() { super(OS.DARWIN); } @Override public String mapLibraryName(String libName) { // // A specific version was requested - use as is for search // if (libName.matches(getLibraryNamePattern())) { return libName; } return "lib" + libName + ".dylib"; } @Override public String getLibraryNamePattern() { return "lib.*\\.(dylib|jnilib)$"; } @Override public String getName() { return "Darwin"; } public final int longSize() { return getCPU().dataModel; } } /** * A {@link Platform} subclass representing the Windows system. */ private static final class Windows extends Platform { public Windows() { super(OS.WINDOWS); } @Override public String getLibraryNamePattern() { return ".*\\.dll$"; } public final int longSize() { return 32; } } private static boolean startsWithIgnoreCase(String s1, String s2) { return s1.startsWith(s2) || s1.toUpperCase(LOCALE).startsWith(s2.toUpperCase(LOCALE)) || s1.toLowerCase(LOCALE).startsWith(s2.toLowerCase(LOCALE)); } } jffi-1.2.7/src/main/java/com/kenai/jffi/Struct.java000066400000000000000000000076611247047424400220270ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Describes the layout of a C struct */ public final class Struct extends Aggregate { private static final Map, StructReference> structCache = new ConcurrentHashMap, StructReference>(); private static final ReferenceQueue structReferenceQueue = new ReferenceQueue(); /* Keep a strong reference to the field types so they do not GCed */ @SuppressWarnings({"UnusedDeclaration", "FieldCanBeLocal"}) private final Type[] fields; public static Struct newStruct(Type... fields) { List fieldsList = Arrays.asList(fields); StructReference ref = structCache.get(fieldsList); Struct s = ref != null ? ref.get() : null; if (s != null) { return s; } // Cull any dead references while ((ref = (StructReference) structReferenceQueue.poll()) != null) { structCache.remove(ref.fieldsList); } structCache.put(fieldsList, new StructReference(s = new Struct(Foreign.getInstance(), fields), structReferenceQueue, fieldsList)); return s; } /** * Creates a new C struct layout description. * * @param fields The fields contained in the struct. */ private Struct(Foreign foreign, Type... fields) { super(foreign, foreign.newStruct(Type.nativeHandles(fields), false)); this.fields = fields.clone(); } /** * Creates a new C struct layout description. * * @param fields The fields contained in the struct. */ @Deprecated public Struct(Type... fields) { super(Foreign.getInstance(), Foreign.getInstance().newStruct(Type.nativeHandles(fields), false)); this.fields = fields.clone(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; return Arrays.equals(fields, ((Struct) o).fields); } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + Arrays.hashCode(fields); return result; } private static final class StructReference extends WeakReference { List fieldsList; private StructReference(Struct struct, ReferenceQueue referenceQueue, List fieldsList) { super(struct, referenceQueue); this.fieldsList = fieldsList; } } } jffi-1.2.7/src/main/java/com/kenai/jffi/Type.java000066400000000000000000000220261247047424400214540ustar00rootroot00000000000000/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.util.List; /** * Native parameter and return types. */ public abstract class Type { /** The native void type */ public static final Type VOID = builtin(NativeType.VOID); /** The native float type */ public static final Type FLOAT = builtin(NativeType.FLOAT); /** The native double type */ public static final Type DOUBLE = builtin(NativeType.DOUBLE); /** The native long double type */ public static final Type LONGDOUBLE = builtin(NativeType.LONGDOUBLE); /** The native unsigned 8 bit integer type */ public static final Type UINT8 = builtin(NativeType.UINT8); /** The native signed 8 bit integer type */ public static final Type SINT8 = builtin(NativeType.SINT8); /** The native unsigned 16 bit integer type */ public static final Type UINT16 = builtin(NativeType.UINT16); /** The native signed 16 bit integer type */ public static final Type SINT16 = builtin(NativeType.SINT16); /** The native unsigned 32 bit integer type */ public static final Type UINT32 = builtin(NativeType.UINT32); /** The native signed 32 bit integer type */ public static final Type SINT32 = builtin(NativeType.SINT32); /** The native unsigned 64 bit integer type */ public static final Type UINT64 = builtin(NativeType.UINT64); /** The native signed 64 bit integer type */ public static final Type SINT64 = builtin(NativeType.SINT64); /** The native memory address type */ public static final Type POINTER = builtin(NativeType.POINTER); /** The native unsigned char type */ public static final Type UCHAR = UINT8; /** The native signed char type */ public static final Type SCHAR = SINT8; /** The native unsigned short integer type */ public static final Type USHORT = UINT16; /** The native signed short integer type */ public static final Type SSHORT = SINT16; /** The native unsigned integer type */ public static final Type UINT = UINT32; /** The native signed integer type */ public static final Type SINT = SINT32; /** The native unsigned long integer type */ public static final Type ULONG = builtin(NativeType.ULONG); /** The native signed long integer type */ public static final Type SLONG = builtin(NativeType.SLONG); /** The native unsigned long long integer type */ public static final Type ULONG_LONG = UINT64; /** The native signed long long integer type */ public static final Type SLONG_LONG = SINT64; private int type = 0; private int size = 0; private int alignment = 0; private volatile long handle = 0; /** * Gets the FFI type enum value for this Type * * @return An integer representing the FFI type. */ public final int type() { return type != 0 ? type : resolveType(); } /** * Gets the native address of the ffi_type struct for this Type * * @return The address of the ffi_type structure */ final long handle() { return handle != 0 ? handle : resolveHandle(); } /** * Gets the size of this type. * * @return The size of this type, in bytes. */ public final int size() { return size != 0 ? size : resolveSize(); } /** * Gets the alignment of this type. * * @return The alignment of this type, in bytes. */ public final int alignment() { return alignment != 0 ? alignment : resolveAlignment(); } private int resolveType() { return type = getTypeInfo().type; } private int resolveSize() { return size = getTypeInfo().size; } private int resolveAlignment() { return alignment = getTypeInfo().alignment; } private long resolveHandle() { return handle = getTypeInfo().handle; } abstract TypeInfo getTypeInfo(); @Override public boolean equals(Object obj) { return (obj instanceof Type) && ((Type) obj).handle() == handle(); } @Override public int hashCode() { int hash = 3; hash = 67 * hash + (int) (this.handle() ^ (this.handle() >>> 32)); return hash; } /** * Converts an array of Type objects into an array of pointers to * ffi_type structures. * * @param types An array of Type objects * @return An array of native ffi_type handles. */ static long[] nativeHandles(Type[] types) { long[] nativeTypes = new long[types.length]; for (int i = 0; i < types.length; ++i) { nativeTypes[i] = types[i].handle(); } return nativeTypes; } /** * Converts a list of Type objects into an array of pointers to * ffi_type structures. * * @param types A list of Type objects * @return An array of native ffi_type handles. */ static long[] nativeHandles(List types) { long[] nativeTypes = new long[types.size()]; for (int i = 0; i < nativeTypes.length; ++i) { nativeTypes[i] = types.get(i).handle(); } return nativeTypes; } /** * Creates a Type instance for builtin types. * * @param nativeType The builtin type enum. * @return A Type instance. */ private static Type builtin(NativeType nativeType) { return new Builtin(nativeType); } /** * Types that are built-in to libffi. */ static final class Builtin extends Type { private final NativeType nativeType; private TypeInfo typeInfo; private Builtin(NativeType nativeType) { this.nativeType = nativeType; } TypeInfo getTypeInfo() { return typeInfo != null ? typeInfo : lookupTypeInfo(); } private TypeInfo lookupTypeInfo() { try { Foreign foreign = Foreign.getInstance(); long handle = foreign.lookupBuiltinType(nativeType.ffiType); if (handle == 0L) { throw new NullPointerException("invalid handle for native type " + nativeType); } return typeInfo = new TypeInfo(handle, foreign.getTypeType(handle), foreign.getTypeSize(handle), foreign.getTypeAlign(handle)); } catch (Throwable error) { UnsatisfiedLinkError ule = new UnsatisfiedLinkError("could not get native definition for type: " + nativeType); error.initCause(error); throw ule; } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; Builtin builtin = (Builtin) o; if (nativeType != builtin.nativeType) return false; return true; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + nativeType.hashCode(); return result; } } /** * This is a lazy loaded cache of builtin type info, so we can still have * Type.VOID as a public static variable without it causing the * native library to load. */ static final class TypeInfo { /** The FFI type of this type */ final int type; /** The size in bytes of this type */ final int size; /** The minimum alignment of this type */ final int alignment; /** The address of this type's ffi_type structure */ final long handle; TypeInfo(long handle, int type, int size, int alignment) { this.handle = handle; this.type = type; this.size = size; this.alignment = alignment; } } } jffi-1.2.7/src/main/java/com/kenai/jffi/Union.java000066400000000000000000000046721247047424400216320ustar00rootroot00000000000000/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Alternatively, you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this work. If not, see . */ package com.kenai.jffi; import java.util.Arrays; /** * Describes the layout of a C union */ public final class Union extends Aggregate { /* Keep a strong reference to the field types so they do not GCed */ @SuppressWarnings({"UnusedDeclaration", "FieldCanBeLocal"}) private final Type[] fields; public static Union newUnion(Type... fields) { return new Union(fields); } /** * Creates a new C union layout description. * * @param fields The fields contained in the union. */ public Union(Type... fields) { super(Foreign.getInstance(), Foreign.getInstance().newStruct(Type.nativeHandles(fields), true)); this.fields = fields.clone(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; Union union = (Union) o; return Arrays.equals(fields, union.fields); } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (fields != null ? Arrays.hashCode(fields) : 0); return result; } } jffi-1.2.7/src/main/java/com/kenai/jffi/Util.java000066400000000000000000000005261247047424400214510ustar00rootroot00000000000000package com.kenai.jffi; public final class Util { private Util() {} /** * Aligns an address to a boundary * * @param v The address to roundup * @param a The boundary to align to. * @return The aligned address. */ static int ffi_align(int v, int a) { return ((v - 1) | (a - 1)) + 1; } } jffi-1.2.7/src/main/java/com/kenai/jffi/internal/000077500000000000000000000000001247047424400215025ustar00rootroot00000000000000jffi-1.2.7/src/main/java/com/kenai/jffi/internal/StubLoader.java000066400000000000000000000311421247047424400244120ustar00rootroot00000000000000/* * Copyright (C) 2011 Wayne Meissner * * This file is part of jffi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.kenai.jffi.internal; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.Arrays; import java.util.Properties; /** * Loads the native stub library. This is intended to only ever be called * reflectively, so it cannot access other jffi classes. */ public class StubLoader { public final static int VERSION_MAJOR = getVersionField("MAJOR"); public final static int VERSION_MINOR = getVersionField("MINOR"); private static final String versionClassName = "com.kenai.jffi.Version"; private static final java.util.Locale LOCALE = java.util.Locale.ENGLISH; private static final String bootPropertyFilename = "boot.properties"; private static final String bootLibraryPropertyName = "jffi.boot.library.path"; private static final String stubLibraryName = String.format("jffi-%d.%d", VERSION_MAJOR, VERSION_MINOR); private static final OS OS_ = determineOS(); private static final CPU CPU_ = determineCPU(); private static volatile Throwable failureCause = null; private static volatile boolean loaded = false; public static final boolean isLoaded() { return loaded; } public static final Throwable getFailureCause() { return failureCause; } public enum OS { /** MacOSX */ DARWIN, /** FreeBSD */ FREEBSD, /** NetBSD */ NETBSD, /** OpenBSD */ OPENBSD, /** Linux */ LINUX, /** Solaris (and OpenSolaris) */ SOLARIS, /** The evil borg operating system */ WINDOWS, /** IBM AIX */ AIX, /** IBM zOS **/ ZLINUX, /** No idea what the operating system is */ UNKNOWN; @Override public String toString() { return name().toLowerCase(LOCALE); } } /** * The common names of cpu architectures. * * Note The names of the enum values are used in other parts of the * code to determine where to find the native stub library. Do not rename. */ public enum CPU { /** Intel ia32 */ I386, /** AMD 64 bit (aka EM64T/X64) */ X86_64, /** Power PC 32 bit */ PPC, /** Power PC 64 bit */ PPC64, /** Sun sparc 32 bit */ SPARC, /** Sun sparc 64 bit */ SPARCV9, /** IBM zSeries S/390 64 bit */ S390X, /** ARM */ ARM, /** Unknown CPU */ UNKNOWN; @Override public String toString() { return name().toLowerCase(LOCALE); } } /** * Determines the operating system jffi is running on * * @return An member of the OS enum. */ private static OS determineOS() { String osName = System.getProperty("os.name").split(" ")[0]; if (startsWithIgnoreCase(osName, "mac") || startsWithIgnoreCase(osName, "darwin")) { return OS.DARWIN; } else if (startsWithIgnoreCase(osName, "linux")) { return OS.LINUX; } else if (startsWithIgnoreCase(osName, "sunos") || startsWithIgnoreCase(osName, "solaris")) { return OS.SOLARIS; } else if (startsWithIgnoreCase(osName, "aix")) { return OS.AIX; } else if (startsWithIgnoreCase(osName, "openbsd")) { return OS.OPENBSD; } else if (startsWithIgnoreCase(osName, "freebsd")) { return OS.FREEBSD; } else if (startsWithIgnoreCase(osName, "windows")) { return OS.WINDOWS; } else { return OS.UNKNOWN; } } /** * Determines the CPU architecture the JVM is running on. * * This normalizes all the variations that are equivalent (e.g. i386, x86, i86pc) * into a common cpu type. * * @return A member of the CPU enum. */ private static final CPU determineCPU() { String archString = System.getProperty("os.arch", "unknown"); if (equalsIgnoreCase("x86", archString) || equalsIgnoreCase("i386", archString) || equalsIgnoreCase("i86pc", archString)) { return CPU.I386; } else if (equalsIgnoreCase("x86_64", archString) || equalsIgnoreCase("amd64", archString)) { return CPU.X86_64; } else if (equalsIgnoreCase("ppc", archString) || equalsIgnoreCase("powerpc", archString)) { return CPU.PPC; } else if (equalsIgnoreCase("ppc64", archString) || equalsIgnoreCase("powerpc64", archString)) { return CPU.PPC64; } else if (equalsIgnoreCase("s390", archString) || equalsIgnoreCase("s390x", archString)) { return CPU.S390X; } else if (equalsIgnoreCase("arm", archString)) { return CPU.ARM; } // Try to find by lookup up in the CPU list for (CPU cpu : CPU.values()) { if (equalsIgnoreCase(cpu.name(), archString)) { return cpu; } } return CPU.UNKNOWN; } public static CPU getCPU() { return CPU_; } public static OS getOS() { return OS_; } /** * Gets the name of the stub library. * * @return The name of the stub library as a String */ private static String getStubLibraryName() { return stubLibraryName; } /** * Gets the name of this Platform. * * @return The name of this platform. */ public static String getPlatformName() { if (getOS().equals(OS.DARWIN)) { return "Darwin"; } String osName = System.getProperty("os.name").split(" ")[0]; return getCPU().name().toLowerCase(LOCALE) + "-" + osName; } /** * Gets the path within the jar file of the stub native library. * * @return The path of the jar file. */ private static String getStubLibraryPath() { return "jni/" + getPlatformName() + "/"+ System.mapLibraryName(stubLibraryName); } public StubLoader() {} /** * Loads the stub library */ static void load() { final String libName = getStubLibraryName(); String bootPath = getBootPath(); if (bootPath != null && loadFromBootPath(libName, bootPath)) { return; } String libraryPath = System.getProperty("java.library.path"); if (libraryPath != null && loadFromBootPath(libName, libraryPath)) { return; } loadFromJar(); } private static String getBootPath() { String bootPath = System.getProperty(bootLibraryPropertyName); if (bootPath != null) { return bootPath; } InputStream is = getResourceAsStream(bootPropertyFilename); if (is != null) { Properties p = new Properties(); try { p.load(is); return p.getProperty(bootLibraryPropertyName); } catch (IOException ex) { } finally { try { is.close(); } catch (IOException ex) { throw new RuntimeException(ex); } } } return null; } private static String getAlternateLibraryPath(String path) { if (path.endsWith("dylib")) { return path.substring(0, path.lastIndexOf("dylib")) + "jnilib"; } else { return path.substring(0, path.lastIndexOf("jnilib")) + "dylib"; } } private static boolean loadFromBootPath(String libName, String bootPath) { String[] dirs = bootPath.split(File.pathSeparator); for (int i = 0; i < dirs.length; ++i) { String soname = System.mapLibraryName(libName); // First try to load /${cpu}-${os}/libjffi-x.y.so, then fallback to /libjffi-x.y.so File stub = new File(new File(dirs[i], getPlatformName()), soname); if (!stub.isFile()) { stub = new File(new File(dirs[i]), soname); } String path = stub.getAbsolutePath(); try { System.load(path); return true; } catch (UnsatisfiedLinkError ex) { } if (getOS() == OS.DARWIN) { try { System.load(getAlternateLibraryPath(path)); return true; } catch (UnsatisfiedLinkError ex) {} } } return false; } private static void loadFromJar() { InputStream is = getStubLibraryStream(); File dstFile = null; FileOutputStream os = null; try { dstFile = File.createTempFile("jffi", null); dstFile.deleteOnExit(); os = new FileOutputStream(dstFile); ReadableByteChannel srcChannel = Channels.newChannel(is); for (long pos = 0; is.available() > 0; ) { pos += os.getChannel().transferFrom(srcChannel, pos, Math.max(4096, is.available())); } } catch (IOException ex) { throw new UnsatisfiedLinkError(ex.getMessage()); } finally { try { if (os != null) { os.close(); } is.close(); } catch (IOException ex) { throw new RuntimeException(ex); } } System.load(dstFile.getAbsolutePath()); } /** * Gets an InputStream representing the stub library image stored in * the jar file. * * @return A new InputStream */ private static InputStream getStubLibraryStream() { String stubPath = getStubLibraryPath(); String[] paths = { stubPath, "/" + stubPath }; for (String path : paths) { InputStream is = getResourceAsStream(path); // On MacOS, the stub might be named .dylib or .jnilib - cater for both if (is == null && getOS() == OS.DARWIN) { is = getResourceAsStream(getAlternateLibraryPath(path)); } if (is != null) { return is; } } throw new UnsatisfiedLinkError("could not locate stub library" + " in jar file. Tried " + Arrays.deepToString(paths)); } private static InputStream getResourceAsStream(String resourceName) { // try both our classloader and context classloader ClassLoader[] cls = new ClassLoader[] { ClassLoader.getSystemClassLoader(), StubLoader.class.getClassLoader(), Thread.currentThread().getContextClassLoader() }; for (ClassLoader cl : cls) { // skip null classloader (e.g. boot or null context loader) if (cl == null) { continue; } InputStream is; if ((is = cl.getResourceAsStream(resourceName)) != null) { return is; } } return null; } private static int getVersionField(String name) { try { Class c = Class.forName(versionClassName); return (Integer) c.getField(name).get(c); } catch (Throwable t) { throw new RuntimeException(t); } } private static boolean startsWithIgnoreCase(String s1, String s2) { return s1.startsWith(s2) || s1.toUpperCase(LOCALE).startsWith(s2.toUpperCase(LOCALE)) || s1.toLowerCase(LOCALE).startsWith(s2.toLowerCase(LOCALE)); } private static boolean equalsIgnoreCase(String s1, String s2) { return s1.equalsIgnoreCase(s2) || s1.toUpperCase(LOCALE).equals(s2.toUpperCase(LOCALE)) || s1.toLowerCase(LOCALE).equals(s2.toLowerCase(LOCALE)); } static { try { load(); loaded = true; } catch (Throwable t) { failureCause = t; } } } jffi-1.2.7/src/test/000077500000000000000000000000001247047424400142155ustar00rootroot00000000000000jffi-1.2.7/src/test/java/000077500000000000000000000000001247047424400151365ustar00rootroot00000000000000jffi-1.2.7/src/test/java/com/000077500000000000000000000000001247047424400157145ustar00rootroot00000000000000jffi-1.2.7/src/test/java/com/kenai/000077500000000000000000000000001247047424400170035ustar00rootroot00000000000000jffi-1.2.7/src/test/java/com/kenai/jffi/000077500000000000000000000000001247047424400177215ustar00rootroot00000000000000jffi-1.2.7/src/test/java/com/kenai/jffi/ClosureTest.java000066400000000000000000000516621247047424400230520ustar00rootroot00000000000000 package com.kenai.jffi; import com.kenai.jffi.UnitHelper.InvokerType; import com.kenai.jffi.UnitHelper.Address; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class ClosureTest { private static interface LibClosureTest { void testClosureVrV(Address closure); byte testClosureVrB(Address closure); short testClosureVrS(Address closure); int testClosureVrI(Address closure); long testClosureVrL(Address closure); float testClosureVrF(Address closure); double testClosureVrD(Address closure); void testClosureTrV(Address closure, Address struct); void testClosureBrV(Address closure, byte value); void testClosureSrV(Address closure, short value); void testClosureIrV(Address closure, int value); void testClosureLrV(Address closure, long value); void testClosureFrV(Address closure, float value); void testClosureDrV(Address closure, double value); void testThreadedClosureVrV(Address closure, int count); } private LibClosureTest lib, fastint, fastlong, fastnum; public ClosureTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } private static boolean isFastLongSupported() { return Platform.getPlatform().getCPU() == Platform.CPU.I386 || Platform.getPlatform().getCPU() == Platform.CPU.X86_64; } private static boolean isFastIntSupported() { return Platform.getPlatform().getCPU() == Platform.CPU.I386 || Platform.getPlatform().getCPU() == Platform.CPU.X86_64; } @Before public void setUp() { lib = UnitHelper.loadTestLibrary(LibClosureTest.class, InvokerType.Default); fastlong = UnitHelper.loadTestLibrary(LibClosureTest.class, isFastLongSupported() ? InvokerType.FastLong : InvokerType.Default); fastnum = UnitHelper.loadTestLibrary(LibClosureTest.class, InvokerType.FastNumeric); fastint = UnitHelper.loadTestLibrary(LibClosureTest.class, isFastIntSupported() ? InvokerType.FastLong : InvokerType.Default); } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} private void testClosureVrV(LibClosureTest lib) { final boolean called[] = { false }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[0], CallingConvention.DEFAULT); lib.testClosureVrV(new Address(handle)); assertTrue("Closure not called", called[0]); } @Test public void defaultClosureVrV() throws Throwable { testClosureVrV(lib); } @Test public void fastIntClosureVrV() throws Throwable { if (Platform.getPlatform().addressSize() == 32) { testClosureVrV(fastint); } } @Test public void fastLongClosureVrV() throws Throwable { testClosureVrV(fastlong); } private void testThreadedClosureVrV(LibClosureTest lib, int count) { final boolean called[] = { false }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[0], CallingConvention.DEFAULT); lib.testThreadedClosureVrV(new Address(handle), count); assertTrue("Closure not called", called[0]); } @Test public void defaultThreadedClosureVrV() throws Throwable { testThreadedClosureVrV(lib, 10000); } private void testClosureVrB(LibClosureTest lib) { final boolean called[] = { false }; final byte MAGIC = (byte) 0x12; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setByteReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.SINT8, new Type[0], CallingConvention.DEFAULT); byte retval = lib.testClosureVrB(new Address(handle)); assertTrue("Closure not called", called[0]); assertEquals("Wrong value returned by closure", MAGIC, retval); } @Test public void defaultClosureVrB() throws Throwable { testClosureVrB(lib); } @Test public void fastIntClosureVrB() throws Throwable { testClosureVrB(fastint); } @Test public void fastLongClosureVrB() throws Throwable { testClosureVrB(fastlong); } private void testClosureVrS(LibClosureTest lib) { final boolean called[] = { false }; final short MAGIC = (byte) 0x1234; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setShortReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.SINT32, new Type[0], CallingConvention.DEFAULT); short retval = lib.testClosureVrS(new Address(handle)); assertTrue("Closure not called", called[0]); assertEquals("Wrong value returned by closure", MAGIC, retval); } @Test public void defaultClosureVrS() throws Throwable { testClosureVrS(lib); } @Test public void fastIntClosureVrS() throws Throwable { testClosureVrS(fastint); } @Test public void fastLongClosureVrS() throws Throwable { testClosureVrS(fastlong); } private void testClosureVrI(LibClosureTest lib) { final boolean called[] = { false }; final int MAGIC = 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setIntReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.SINT64, new Type[0], CallingConvention.DEFAULT); int retval = lib.testClosureVrI(new Address(handle)); assertTrue("Closure not called", called[0]); assertEquals("Wrong value returned by closure", MAGIC, retval); } @Test public void defaultClosureVrI() throws Throwable { testClosureVrI(lib); } @Test public void fastIntClosureVrI() throws Throwable { testClosureVrI(fastint); } @Test public void fastLongClosureVrI() throws Throwable { testClosureVrI(fastlong); } private void testClosureVrL(LibClosureTest lib) { final boolean called[] = { false }; final long MAGIC = 0x12345678cafebabeL; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setLongReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.SINT64, new Type[0], CallingConvention.DEFAULT); long retval = lib.testClosureVrL(new Address(handle)); assertTrue("Closure not called", called[0]); assertEquals("Wrong value returned by closure", MAGIC, retval); } @Test public void defaultClosureVrL() throws Throwable { testClosureVrL(lib); } @Test public void fastLongClosureVrL() throws Throwable { testClosureVrL(fastlong); } private void testClosureVrF(LibClosureTest lib) { final boolean called[] = { false }; final float MAGIC = (float) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setFloatReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.FLOAT, new Type[0], CallingConvention.DEFAULT); float retval = lib.testClosureVrF(new Address(handle)); assertTrue("Closure not called", called[0]); assertTrue("Wrong value returned by closure", (MAGIC -retval) < 0.0001); } @Test public void defaultClosureVrF() throws Throwable { testClosureVrF(lib); } private void testClosureVrD(LibClosureTest lib) { final boolean called[] = { false }; final double MAGIC = (double) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setDoubleReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.DOUBLE, new Type[0], CallingConvention.DEFAULT); double retval = lib.testClosureVrD(new Address(handle)); assertTrue("Closure not called", called[0]); assertTrue("Wrong value returned by closure", (MAGIC -retval) < 0.0001); } @Test public void defaultClosureVrD() throws Throwable { testClosureVrD(lib); } @Test public void fastNumericClosureVrD() throws Throwable { testClosureVrD(fastnum); } @Test public void testClosureTrV() throws Throwable { final boolean called[] = { false }; final byte[] s8 = { 0 }; final float[] f32 = { 0 }; final int[] s32 = { 0 }; final byte S8_MAGIC = (byte) 0xfe; final int S32_MAGIC = (int) 0xdeadbeef; final float F32_MAGIC = (float) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; long struct = buffer.getStruct(0); s8[0] = MemoryIO.getInstance().getByte(struct); f32[0] = MemoryIO.getInstance().getFloat(struct + 4); s32[0] = MemoryIO.getInstance().getInt(struct + 8); } }; Struct s8f32s32 = new Struct(new Type[] { Type.SINT8, Type.FLOAT, Type.SINT32 }); Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { s8f32s32, Type.POINTER }, CallingConvention.DEFAULT); long struct = MemoryIO.getInstance().allocateMemory(12, true); MemoryIO.getInstance().putByte(struct, S8_MAGIC); MemoryIO.getInstance().putFloat(struct + 4, F32_MAGIC); MemoryIO.getInstance().putInt(struct + 8, S32_MAGIC); lib.testClosureTrV(new Address(handle), new Address(struct)); assertTrue("Closure not called", called[0]); assertEquals("Wrong s8 field value", S8_MAGIC, s8[0]); assertEquals("Wrong s32 field value", S32_MAGIC, s32[0]); assertTrue("Wrong f32 field value", (F32_MAGIC - f32[0]) < 0.0001); } @Test public void testClosureVrTFromArray() throws Throwable { final boolean called[] = { false }; final byte S8_MAGIC = (byte) 0xfe; final int S32_MAGIC = (int) 0xdeadbeef; final float F32_MAGIC = (float) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; ByteBuffer retVal = ByteBuffer.allocate(12).order(ByteOrder.nativeOrder()); retVal.put(0, S8_MAGIC); retVal.putFloat(4, F32_MAGIC); retVal.putInt(8, S32_MAGIC); buffer.setStructReturn(retVal.array(), retVal.arrayOffset()); } }; Struct s8f32s32 = new Struct(new Type[] { Type.SINT8, Type.FLOAT, Type.SINT32 }); Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, s8f32s32, new Type[] { }, CallingConvention.DEFAULT); Function f = new Function(UnitHelper.findSymbol("testClosureVrT").address, s8f32s32, new Type[] { Type.POINTER }); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(f); paramBuffer.putAddress(handle.getAddress()); ByteBuffer retval = ByteBuffer.wrap(Invoker.getInstance().invokeStruct(f, paramBuffer)); retval.order(ByteOrder.nativeOrder()); assertTrue("Closure not called", called[0]); assertEquals("Wrong s8 field value", S8_MAGIC, retval.get(0)); assertEquals("Wrong s32 field value", S32_MAGIC, retval.getInt(8)); assertTrue("Wrong f32 field value", (F32_MAGIC - retval.getFloat(4)) < 0.0001); } @Test public void testClosureVrTFromPointer() throws Throwable { final boolean called[] = { false }; final byte S8_MAGIC = (byte) 0xfe; final int S32_MAGIC = (int) 0xdeadbeef; final float F32_MAGIC = (float) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; long struct = MemoryIO.getInstance().allocateMemory(12, true); MemoryIO.getInstance().putByte(struct, S8_MAGIC); MemoryIO.getInstance().putFloat(struct + 4, F32_MAGIC); MemoryIO.getInstance().putInt(struct + 8, S32_MAGIC); buffer.setStructReturn(struct); } }; Struct s8f32s32 = new Struct(new Type[] { Type.SINT8, Type.FLOAT, Type.SINT32 }); Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, s8f32s32, new Type[] { }, CallingConvention.DEFAULT); Function f = new Function(UnitHelper.findSymbol("testClosureVrT").address, s8f32s32, new Type[] { Type.POINTER }); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(f); paramBuffer.putAddress(handle.getAddress()); ByteBuffer retval = ByteBuffer.wrap(Invoker.getInstance().invokeStruct(f, paramBuffer)); retval.order(ByteOrder.nativeOrder()); assertTrue("Closure not called", called[0]); assertEquals("Wrong s8 field value", S8_MAGIC, retval.get(0)); assertEquals("Wrong s32 field value", S32_MAGIC, retval.getInt(8)); assertTrue("Wrong f32 field value", (F32_MAGIC - retval.getFloat(4)) < 0.0001); } private void testClosureBrV(LibClosureTest lib) { final boolean called[] = { false }; final byte MAGIC = (byte) 0x12; final byte[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getByte(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.SINT8 }, CallingConvention.DEFAULT); lib.testClosureBrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertEquals("Wrong value passed to closure", MAGIC, data[0]); } @Test public void defaultClosureBrV() throws Throwable { testClosureBrV(lib); } @Test public void fastIntClosureBrV() throws Throwable { testClosureBrV(fastint); } @Test public void fastLongClosureBrV() throws Throwable { testClosureBrV(fastlong); } private void testClosureSrV(LibClosureTest lib) { final boolean called[] = { false }; final short MAGIC = (byte) 0x1234; final short[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getShort(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.SINT16 }, CallingConvention.DEFAULT); lib.testClosureSrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertEquals("Wrong value passed to closure", MAGIC, data[0]); } @Test public void defaultClosureSrV() throws Throwable { testClosureSrV(lib); } @Test public void fastIntClosureSrV() throws Throwable { testClosureSrV(fastint); } @Test public void fastLongClosureSrV() throws Throwable { testClosureSrV(fastlong); } private void testClosureIrV(LibClosureTest lib) { final boolean called[] = { false }; final int MAGIC = 0x12345678; final int[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getInt(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.SINT32 }, CallingConvention.DEFAULT); lib.testClosureIrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertEquals("Wrong value passed to closure", MAGIC, data[0]); } @Test public void defaultClosureIrV() throws Throwable { testClosureIrV(lib); } @Test public void fastIntClosureIrV() throws Throwable { testClosureIrV(fastint); } @Test public void fastLongClosureIrV() throws Throwable { testClosureIrV(fastlong); } private void testClosureLrV(LibClosureTest lib) { final boolean called[] = { false }; final long MAGIC = 0x12345678fee1deadL; final long[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getLong(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.SINT64 }, CallingConvention.DEFAULT); lib.testClosureLrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertEquals("Wrong value passed to closure", MAGIC, data[0]); } @Test public void defaultClosureLrV() throws Throwable { testClosureLrV(lib); } @Test public void fastLongClosureLrV() throws Throwable { testClosureLrV(fastlong); } private void testClosureFrV(LibClosureTest lib) { final boolean called[] = { false }; final float MAGIC = (float) 0x12345678; final float[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getFloat(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.FLOAT }, CallingConvention.DEFAULT); lib.testClosureFrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertTrue("Wrong value passed to closure", (MAGIC - data[0]) < 0.0001); } @Test public void defaultClosureFrV() throws Throwable { testClosureFrV(lib); } private void testClosureDrV(LibClosureTest lib) { final boolean called[] = { false }; final double MAGIC = (double) 0x12345678; final double[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getDouble(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.DOUBLE }, CallingConvention.DEFAULT); lib.testClosureDrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertTrue("Wrong value passed to closure", (MAGIC - data[0]) < 0.0001); } @Test public void defaultClosureDrV() throws Throwable { testClosureDrV(lib); } @Test public void allocateLots() throws Throwable { ClosureManager m = ClosureManager.getInstance(); List handles = new ArrayList(); for (int i = 0; i < 1000; ++i) { Closure c = new Closure() { public void invoke(Buffer buffer) { throw new UnsupportedOperationException("Not supported yet."); } }; handles.add(m.newClosure(c, Type.FLOAT, new Type[0], CallingConvention.DEFAULT)); } for (Closure.Handle h : handles) { h.dispose(); } handles.clear(); for (int i = 0; i < 1000; ++i) { Closure c = new Closure() { public void invoke(Buffer buffer) { throw new UnsupportedOperationException("Not supported yet."); } }; handles.add(m.newClosure(c, Type.FLOAT, new Type[0], CallingConvention.DEFAULT)); } } static class Proxy { public void invoke(long retval, long args) { } } } jffi-1.2.7/src/test/java/com/kenai/jffi/ForeignTest.java000066400000000000000000000065201247047424400230200ustar00rootroot00000000000000 package com.kenai.jffi; import java.lang.reflect.Method; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * Test internals of the Foreign class */ public class ForeignTest { public ForeignTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void version() { final int VERSION = Foreign.VERSION_MAJOR << 16 | Foreign.VERSION_MINOR << 8 | Foreign.VERSION_MICRO; int version = Foreign.getInstance().getVersion(); assertEquals("Bad version", VERSION, version); } @Test public void pageSize() { long pageSize = Foreign.getInstance().pageSize(); assertNotSame("Invalid page size", 0, pageSize); } @Test public void mmap() { if (Platform.getPlatform().getOS() != Platform.OS.WINDOWS) { final int SIZE = 123; long addr = Foreign.getInstance().mmap(0, SIZE, Foreign.PROT_READ | Foreign.PROT_WRITE, Foreign.MAP_PRIVATE | Foreign.MAP_ANON, -1, 0); assertNotSame("Failed to allocate memory", -1L, addr); } } @Test public void munmap() { if (Platform.getPlatform().getOS() != Platform.OS.WINDOWS) { final int SIZE = 123; long addr = Foreign.getInstance().mmap(0, SIZE, Foreign.PROT_READ | Foreign.PROT_WRITE, Foreign.MAP_PRIVATE | Foreign.MAP_ANON, -1, 0); assertNotSame("Failed to allocate memory", -1, addr); assertTrue("Failed to free memory", Foreign.getInstance().munmap(addr, SIZE) == 0); } } @Test public void writeToAllocatedMemory() { if (Platform.getPlatform().getOS() != Platform.OS.WINDOWS) { final int SIZE = 257; final byte[] MAGIC = {'t', 'e', 's', 't'}; long addr = Foreign.getInstance().mmap(0, SIZE, Foreign.PROT_READ | Foreign.PROT_WRITE, Foreign.MAP_PRIVATE | Foreign.MAP_ANON, -1, 0); assertNotSame("Failed to allocate memory", -1, addr); MemoryIO.getInstance().putByteArray(addr, MAGIC, 0, MAGIC.length); byte[] tmp = new byte[MAGIC.length]; MemoryIO.getInstance().getByteArray(addr, tmp, 0, MAGIC.length); assertArrayEquals("Incorrect data read back", MAGIC, tmp); assertTrue("Failed to free memory", Foreign.getInstance().munmap(addr, SIZE) == 0); } } static class ClosureProxy { void invoke(Closure.Buffer buf) {} } // @Test public void freeClosure() throws Throwable { // Method m = ClosureProxy.class.getDeclaredMethod("invoke", new Class[] { Closure.Buffer.class}); // long cl = Foreign.getInstance().newClosure(new ClosureProxy(), m, Type.VOID.handle, new long[0], 0); // Foreign.getInstance().freeClosure(cl); // } // @Test public void newNativeMethod() throws Throwable { // Foreign.getInstance().newNativeMethod("test", "()V", 0); // } }jffi-1.2.7/src/test/java/com/kenai/jffi/InvokerTest.java000066400000000000000000000320671247047424400230510ustar00rootroot00000000000000package com.kenai.jffi; import org.junit.Test; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.Arrays; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; /** */ public class InvokerTest { private static final MemoryIO IO = MemoryIO.getInstance(); static Function getFunction(String name, Type returnType, Type... parameterTypes) { UnitHelper.Address fn = UnitHelper.findSymbol(name); return new Function(fn.address, returnType, parameterTypes); } static CallContext getContext(Type returnType, Type... parameterTypes) { return new CallContext(returnType, parameterTypes); } static final long N1 = 0x1eafbeef; static final long N2 = 0x1010dead; static ObjectParameterInfo.ComponentType NATIVE_LONG = Platform.getPlatform().longSize() == 32 ? ObjectParameterInfo.INT : ObjectParameterInfo.LONG; static long getNativeUnsignedLong(UnitHelper.Address ptr) { if (Platform.getPlatform().longSize() == 32) { long n = IO.getInt(ptr.address); return n < 0 ? ((n & 0x7FFFFFFFL) + 0x80000000L) : n; } else { return IO.getLong(ptr.address); } } static void putNativeUnsignedLong(UnitHelper.Address ptr, long value) { if (Platform.getPlatform().longSize() == 32) { IO.putInt(ptr.address, (int) value); } else { IO.putLong(ptr.address, value); } } static Object newNativeUnsignedLongArray(long... values) { if (Platform.getPlatform().longSize() == 32) { int[] iarray = new int[values.length]; for (int i = 0; i < iarray.length; i++) { iarray[i] = (int) values[i]; } return iarray; } else { return values; } } static long getNativeUnsignedLong(Object arr) { return getNativeUnsignedLong(arr, 0); } static long getNativeUnsignedLong(Object arr, int idx) { if (long[].class == arr.getClass()) { long[] larr = long[].class.cast(arr); return larr[idx]; } else { int[] iarr = int[].class.cast(arr); long n = iarr[idx]; return n < 0 ? ((n & 0x7FFFFFFFL) + 0x80000000L) : n; } } static long unsigned(long n) { return n < 0 ? ((n & 0x7FFFFFFFL) + 0x80000000L) : n; } static class HeapArrayStrategy extends ObjectParameterStrategy { private int offset, length; HeapArrayStrategy(int offset, int length) { super(HEAP); this.offset = offset; this.length = length; } @Override public long address(Object parameter) { return 0L; } @Override public Object object(Object parameter) { return parameter; } @Override public int offset(Object parameter) { return offset; } @Override public int length(Object parameter) { return length; } } static class DirectStrategy extends ObjectParameterStrategy { DirectStrategy() { super(DIRECT); } @Override public long address(Object parameter) { return ((UnitHelper.Address) parameter).address; } @Override public Object object(Object parameter) { throw new IllegalStateException("not a heap object"); } @Override public int offset(Object parameter) { throw new IllegalStateException("not a heap object"); } @Override public int length(Object parameter) { throw new IllegalStateException("not a heap object"); } } static class NativeInvoker extends Invoker { NativeInvoker() { super(Foreign.getInstance(), NativeObjectParameterInvoker.getInstance()); } @Override public long invokeAddress(Function function, HeapInvocationBuffer buffer) { return Invoker.getInstance().invokeAddress(function, buffer); } @Override public long invokeAddress(CallContext ctx, long function, HeapInvocationBuffer buffer) { return Invoker.getInstance().invokeAddress(ctx, function, buffer); } } static class HeapInvoker extends Invoker { HeapInvoker() { super(Foreign.getInstance(), HeapObjectParameterInvoker.getInstance()); } @Override public long invokeAddress(Function function, HeapInvocationBuffer buffer) { return Invoker.getInstance().invokeAddress(function, buffer); } @Override public long invokeAddress(CallContext ctx, long function, HeapInvocationBuffer buffer) { return Invoker.getInstance().invokeAddress(ctx, function, buffer); } } public static void invokeO(Invoker invoker) { Function function = getFunction("invokeO", Type.SLONG, Type.POINTER); CallContext ctx = getContext(Type.SLONG, Type.POINTER); Object arr = newNativeUnsignedLongArray(N1); ObjectParameterStrategy strategy = new HeapArrayStrategy(0, 1); ObjectParameterInfo info = ObjectParameterInfo.create(0, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); long ret = invoker.invokeN1(ctx, function.getFunctionAddress(), 0, 1, arr, strategy, info); assertEquals("incorrect return value", N1, unsigned(ret)); assertEquals("incorrect array value", 0xdeadbeefL, getNativeUnsignedLong(arr)); } public static void invokeNO(Invoker invoker) { Function function = getFunction("invokeNO", Type.SLONG, Type.SLONG, Type.POINTER); CallContext ctx = getContext(Type.SLONG, Type.SLONG, Type.POINTER); Object arr = newNativeUnsignedLongArray(N1); ObjectParameterStrategy strategy = new HeapArrayStrategy(0, 1); ObjectParameterInfo info = ObjectParameterInfo.create(1, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); long ret = invoker.invokeN2(ctx, function.getFunctionAddress(), N2, 0L, 1, arr, strategy, info); assertEquals("incorrect return value", N1, unsigned(ret)); assertEquals("incorrect array value", N2, getNativeUnsignedLong(arr)); } public static void invokeON(Invoker invoker) { Function function = getFunction("invokeON", Type.SLONG, Type.POINTER, Type.SLONG); CallContext ctx = getContext(Type.SLONG, Type.POINTER, Type.SLONG); Object arr = newNativeUnsignedLongArray(N1); ObjectParameterStrategy strategy = new HeapArrayStrategy(0, 1); ObjectParameterInfo info = ObjectParameterInfo.create(0, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); long ret = invoker.invokeN2(ctx, function.getFunctionAddress(), 0L, N2, 1, arr, strategy, info); assertEquals("incorrect return value", N1, unsigned(ret)); assertEquals("incorrect array value", N2, getNativeUnsignedLong(arr)); } public static void invokeOO(Invoker invoker) { Function function = getFunction("invokeOO", Type.SLONG, Type.POINTER, Type.POINTER); CallContext ctx = getContext(Type.SLONG, Type.POINTER, Type.POINTER); Object arr1 = newNativeUnsignedLongArray(N1); Object arr2 = newNativeUnsignedLongArray(N2); ObjectParameterStrategy strategy = new HeapArrayStrategy(0, 1); ObjectParameterInfo o1info = ObjectParameterInfo.create(0, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); ObjectParameterInfo o2info = ObjectParameterInfo.create(1, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); long ret = invoker.invokeN2(ctx, function.getFunctionAddress(), 0L, 0L, 2, arr1, strategy, o1info, arr2, strategy, o2info); assertEquals("incorrect array value", N2, getNativeUnsignedLong(arr1)); assertEquals("incorrect array value", N1, getNativeUnsignedLong(arr2)); assertEquals("incorrect return value", unsigned(N1 + N2), unsigned(ret)); } public static void invokeDO(Invoker invoker) { Function function = getFunction("invokeOO", Type.SLONG, Type.POINTER, Type.POINTER); CallContext ctx = getContext(Type.SLONG, Type.POINTER, Type.POINTER); UnitHelper.Address o1 = new UnitHelper.Address(IO.allocateMemory(8, true)); putNativeUnsignedLong(o1, N1); Object o2 = newNativeUnsignedLongArray(N2); ObjectParameterStrategy s1 = new DirectStrategy(); ObjectParameterStrategy s2 = new HeapArrayStrategy(0, 1); ObjectParameterInfo o1info = ObjectParameterInfo.create(0, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); ObjectParameterInfo o2info = ObjectParameterInfo.create(1, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); long ret = invoker.invokeN2(ctx, function.getFunctionAddress(), o1.address, 0L, 1, o1, s1, o1info, o2, s2, o2info); assertEquals("incorrect ptr value", N2, getNativeUnsignedLong(o1)); assertEquals("incorrect array value", N1, getNativeUnsignedLong(o2)); assertEquals("incorrect return value", N1 + N2, unsigned(ret)); } public static void invokeOD(Invoker invoker) { Function function = getFunction("invokeOO", Type.SLONG, Type.POINTER, Type.POINTER); CallContext ctx = getContext(Type.SLONG, Type.POINTER, Type.POINTER); UnitHelper.Address ptr = new UnitHelper.Address(IO.allocateMemory(8, true)); putNativeUnsignedLong(ptr, N2); Object array = newNativeUnsignedLongArray(N1); ObjectParameterStrategy ptrStrategy = new DirectStrategy(); ObjectParameterStrategy arrayStrategy = new HeapArrayStrategy(0, 1); ObjectParameterInfo o1info = ObjectParameterInfo.create(0, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); ObjectParameterInfo o2info = ObjectParameterInfo.create(1, ObjectParameterInfo.ARRAY, NATIVE_LONG, ObjectParameterInfo.IN | ObjectParameterInfo.OUT); long ret = invoker.invokeN2(ctx, function.getFunctionAddress(), 0L, ptr.address, 1, array, arrayStrategy, o1info, ptr, ptrStrategy, o2info); assertEquals("incorrect ptr value", N1, getNativeUnsignedLong(ptr)); assertEquals("incorrect array value", N2, getNativeUnsignedLong(array)); assertEquals("incorrect return value", N1 + N2, unsigned(ret)); } @Test public void invokeNativeO() { invokeO(new NativeInvoker()); } @Test public void invokeHeapO() { invokeO(new HeapInvoker()); } @Test public void invokeNativeNO() { invokeNO(new NativeInvoker()); } @Test public void invokeHeapNO() { invokeNO(new HeapInvoker()); } @Test public void invokeNativeON() { invokeON(new NativeInvoker()); } @Test public void invokeHeapON() { invokeON(new HeapInvoker()); } @Test public void invokeNativeOO() { invokeOO(new NativeInvoker()); } @Test public void invokeHeapOO() { invokeOO(new HeapInvoker()); } @Test public void invokeNativeDO() { invokeDO(new NativeInvoker()); } @Test public void invokeHeapDO() { invokeDO(new HeapInvoker()); } @Test public void invokeNativeOD() { invokeOD(new NativeInvoker()); } @Test public void invokeHeapOD() { invokeOD(new HeapInvoker()); } public static boolean string_equals(Invoker invoker, String s1, String s2) { Function function = getFunction("string_equals", Type.SINT, Type.POINTER, Type.POINTER); CallContext ctx = getContext(Type.SINT, Type.POINTER, Type.POINTER); ByteBuffer s1Buffer = Charset.defaultCharset().encode(CharBuffer.wrap(s1)); ByteBuffer s2Buffer = Charset.defaultCharset().encode(CharBuffer.wrap(s2)); ObjectParameterStrategy s1strategy = new HeapArrayStrategy(s1Buffer.arrayOffset(), s1Buffer.remaining()); ObjectParameterStrategy s2strategy = new HeapArrayStrategy(s2Buffer.arrayOffset(), s2Buffer.remaining()); ObjectParameterInfo o1info = ObjectParameterInfo.create(0, ObjectParameterInfo.ARRAY, ObjectParameterInfo.BYTE, ObjectParameterInfo.IN | ObjectParameterInfo.NULTERMINATE); ObjectParameterInfo o2info = ObjectParameterInfo.create(1, ObjectParameterInfo.ARRAY, ObjectParameterInfo.BYTE, ObjectParameterInfo.IN | ObjectParameterInfo.NULTERMINATE); long ret = invoker.invokeN2(ctx, function.getFunctionAddress(), 0, 0, 2, s1Buffer.array(), s1strategy, o1info, s2Buffer.array(), s2strategy, o2info); return ret != 0; } @Test public void string_equals_heap() { assertTrue("strings not equal", string_equals(new NativeInvoker(), "test", "test")); } } jffi-1.2.7/src/test/java/com/kenai/jffi/JSR292Test.java000066400000000000000000000024121247047424400223160ustar00rootroot00000000000000/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.kenai.jffi; import org.junit.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; /** * */ public class JSR292Test { public JSR292Test() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } @Test public void testInvokeDynamicAvailable() throws Throwable { CallContext context = CallContext.getCallContext(Type.VOID, new Type[0], CallingConvention.DEFAULT, true); InvokeDynamicSupport.Invoker invoker = InvokeDynamicSupport.getFastNumericInvoker(context, 0xdeadbeef); if (Platform.getPlatform().getJavaMajorVersion() >= 7) { assertNotNull("invoke dynamic support should be available on JDK 7+", invoker); assertNotNull(invoker.getMethod()); assertNotNull(invoker.getMethodHandle()); } else { assertNull("invoke dynamic support should not be available on < JDK 7", invoker); } } } jffi-1.2.7/src/test/java/com/kenai/jffi/LibraryTest.java000066400000000000000000000016551247047424400230370ustar00rootroot00000000000000package com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * * @author wayne */ public class LibraryTest { public LibraryTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void dlopen() { String libName = UnitHelper.getCLibraryName(); long handle = Foreign.getInstance().dlopen(libName, Library.LAZY | Library.GLOBAL); assertNotSame("Could not open libc.so", 0L, handle); } } jffi-1.2.7/src/test/java/com/kenai/jffi/MemoryTest.java000066400000000000000000000046101247047424400226750ustar00rootroot00000000000000 package com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class MemoryTest { public MemoryTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void allocateUnaligned() { long memory = MemoryIO.getInstance().allocateMemory(1024, false); assertNotSame("Could not allocate memory", 0L, memory); MemoryIO.getInstance().freeMemory(memory); } @Test public void zeroTerminatedByteArray() { byte[] MAGIC = { 't', 'e', 's', 't' }; long memory = MemoryIO.getInstance().allocateMemory(MAGIC.length + 1, true); MemoryIO.getInstance().putByteArray(memory, MAGIC, 0, MAGIC.length); byte[] string = MemoryIO.getInstance().getZeroTerminatedByteArray(memory); assertArrayEquals(MAGIC, string); } @Test public void zeroTerminatedByteArrayWithLength() { byte[] MAGIC = { 't', 'e', 's', 't' }; long memory = MemoryIO.getInstance().allocateMemory(MAGIC.length + 1, true); MemoryIO.getInstance().putByteArray(memory, MAGIC, 0, MAGIC.length); MemoryIO.getInstance().putByte(memory + 4, (byte) 0xff); byte[] string = MemoryIO.getInstance().getZeroTerminatedByteArray(memory, 4); assertArrayEquals(MAGIC, string); } @Test public void putZeroTerminatedByteArray() { final byte[] DIRTY = { 'd', 'i', 'r', 't', 'y' }; final byte[] MAGIC = { 't', 'e', 's', 't' }; long memory = MemoryIO.getInstance().allocateMemory(MAGIC.length + 1, true); MemoryIO.getInstance().putByteArray(memory, DIRTY, 0, DIRTY.length); MemoryIO.getInstance().putZeroTerminatedByteArray(memory, MAGIC, 0, MAGIC.length); assertArrayEquals("String not written to native memory", MAGIC, MemoryIO.getInstance().getZeroTerminatedByteArray(memory, 4)); assertEquals("String not NUL terminated", (byte)0, MemoryIO.getInstance().getByte(memory + 4)); } }jffi-1.2.7/src/test/java/com/kenai/jffi/NumberTest.java000066400000000000000000000230601247047424400226550ustar00rootroot00000000000000 package com.kenai.jffi; import com.kenai.jffi.UnitHelper.InvokerType; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.math.BigDecimal; import static org.junit.Assert.*; public class NumberTest { private static interface LibNumberTest { byte ret_s8(byte v); byte ret_u8(byte v); short ret_s16(short v); short ret_u16(short v); int ret_s32(int v); int ret_u32(int v); long ret_s64(long v); long ret_u64(long v); float ret_float(float v); double ret_double(double v); BigDecimal ret_f128(BigDecimal v); } private static interface LibM { float powf(float x, float y); float cosf(float x); } public NumberTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } private static final byte[] s8_values = { 0, Byte.MAX_VALUE, Byte.MIN_VALUE, -1 }; private static final byte[] u8_values = { 0, Byte.MAX_VALUE, (byte) 0x80, (byte) 0xff }; private static final short[] s16_values = { 0, Short.MAX_VALUE, Short.MIN_VALUE, -1 }; private static final short[] u16_values = { 0, Short.MAX_VALUE, (short) 0x8000, (short) 0xffff }; private static final int[] s32_values = { 0, Integer.MAX_VALUE, Integer.MIN_VALUE, -1 }; private static final int[] u32_values = { 0, Integer.MAX_VALUE, 0x80000000, 0xffffffff }; private static final long[] s64_values = { 0, Long.MAX_VALUE, Long.MIN_VALUE, -1 }; private static final long[] u64_values = { 0, Long.MAX_VALUE, 0x8000000000000000L, 0xffffffffffffffffL }; @Test public void returnS8() { returnS8(InvokerType.Default); } @Test public void returnU8() { returnU8(InvokerType.Default); } @Test public void returnFastIntS8() { returnS8(InvokerType.FastInt); } @Test public void returnFastIntU8() { returnU8(InvokerType.FastInt); } @Test public void returnFastLongS8() { returnS8(InvokerType.FastLong); } @Test public void returnFastLongU8() { returnU8(InvokerType.FastLong); } @Test public void returnFastNumericS8() { returnS8(InvokerType.FastNumeric); } @Test public void returnFastNumericU8() { returnU8(InvokerType.FastNumeric); } @Test public void returnPointerArrayS8() { returnS8(InvokerType.PointerArray); } @Test public void returnPointerArrayU8() { returnU8(InvokerType.PointerArray); } private void returnS8(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < s8_values.length; ++i) { assertEquals("Value not returned correctly", s8_values[i], lib.ret_s8(s8_values[i])); } } private void returnU8(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < u8_values.length; ++i) { assertEquals("Value not returned correctly", u8_values[i], lib.ret_u8(u8_values[i])); } } @Test public void returnS16() { returnS16(InvokerType.Default); } @Test public void returnFastIntS16() { returnS16(InvokerType.FastInt); } @Test public void returnFastLongS16() { returnS16(InvokerType.FastLong); } @Test public void returnFastNumericS16() { returnS16(InvokerType.FastNumeric); } @Test public void returnPointerArrayS16() { returnS16(InvokerType.PointerArray); } private void returnS16(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < s16_values.length; ++i) { assertEquals("Value not returned correctly", s16_values[i], lib.ret_s16(s16_values[i])); } } @Test public void returnU16() { returnU16(InvokerType.Default); } @Test public void returnFastIntU16() { returnU16(InvokerType.FastInt); } @Test public void returnFastLongU16() { returnU16(InvokerType.FastLong); } @Test public void returnFastNumericU16() { returnU16(InvokerType.FastNumeric); } @Test public void returnPointerArrayU16() { returnU16(InvokerType.PointerArray); } private void returnU16(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < u16_values.length; ++i) { assertEquals("Value not returned correctly", u16_values[i], lib.ret_u16(u16_values[i])); } } @Test public void returnS32() { returnS32(InvokerType.Default); } @Test public void returnFastintS32() { returnS32(InvokerType.FastInt); } @Test public void returnFastLongS32() { returnS32(InvokerType.FastLong); } @Test public void returnFastNumericS32() { returnS32(InvokerType.FastNumeric); } @Test public void returnPointerArrayS32() { returnS32(InvokerType.PointerArray); } private void returnS32(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < s32_values.length; ++i) { assertEquals("Value not returned correctly", s32_values[i], lib.ret_s32(s32_values[i])); } } @Test public void returnU32() { returnU32(InvokerType.Default); } @Test public void returnFastintU32() { returnU32(InvokerType.FastInt); } @Test public void returnFastLongU32() { returnU32(InvokerType.FastLong); } @Test public void returnFastNumericU32() { returnU32(InvokerType.FastNumeric); } @Test public void returnPointerArrayU32() { returnU32(InvokerType.PointerArray); } private void returnU32(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < u32_values.length; ++i) { assertEquals("Value not returned correctly", u32_values[i], lib.ret_u32(u32_values[i])); } } @Test public void returnS64() { returnS64(InvokerType.Default); } @Test public void returnFastLongS64() { returnS64(InvokerType.FastLong); } @Test public void returnFastNumericS64() { returnS64(InvokerType.FastNumeric); } @Test public void returnPointerArrayS64() { returnS64(InvokerType.PointerArray); } private void returnS64(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < s64_values.length; ++i) { assertEquals("Value not returned correctly", s64_values[i], lib.ret_s64(s64_values[i])); } } @Test public void returnU64() { returnU64(InvokerType.Default); } @Test public void returnFastLongU64() { returnU64(InvokerType.FastLong); } @Test public void returnFastNumericU64() { returnU64(InvokerType.FastNumeric); } @Test public void returnPointerArrayU64() { returnU64(InvokerType.PointerArray); } private void returnU64(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < u64_values.length; ++i) { assertEquals("Value not returned correctly", u64_values[i], lib.ret_u64(u64_values[i])); } } @Test public void returnDefaultF32() { returnF32(InvokerType.Default); } @Test public void returnPointerArrayF32() { returnF32(InvokerType.PointerArray); } private void returnF32(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); float[] values = { 0f, 1.0f, -2.0f }; for (int i = 0; i < values.length; ++i) { assertEquals("Value not returned correctly", values[i], lib.ret_float(values[i]), 0.1f); } } @Test public void returnDefaultF64() { returnF64(InvokerType.Default); } private void returnF64(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); double[] values = { 0d, 1.0d, -2.0d }; for (int i = 0; i < values.length; ++i) { assertEquals("Value not returned correctly", values[i], lib.ret_double(values[i]), 0.1f); } } @Test public void returnDefaultF128() { returnF128(InvokerType.Default); } @Test public void returnDefaultF128HighPrecision() { returnF128HighPrecision(InvokerType.Default); } private void returnF128HighPrecision(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); BigDecimal param = new BigDecimal("1.234567890123456789"); BigDecimal result = lib.ret_f128(param); BigDecimal delta = param.subtract(result).abs(); assertTrue(delta.compareTo(new BigDecimal("0.0000000000000000001")) < 0); } private void returnF128(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); double[] values = { 0d, 1.0d, -2.0d }; for (double v : values) { BigDecimal param = BigDecimal.valueOf(v); BigDecimal result = lib.ret_f128(param); BigDecimal delta = param.subtract(result).abs(); assertTrue(delta.compareTo(new BigDecimal("0.1")) < 0); } } } jffi-1.2.7/src/test/java/com/kenai/jffi/ObjectParameterInfoTest.java000066400000000000000000000030041247047424400253040ustar00rootroot00000000000000package com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.util.EnumSet; import static org.junit.Assert.*; /** * */ public class ObjectParameterInfoTest { static int[] possibleFlags = { ObjectParameterInfo.IN, ObjectParameterInfo.OUT, ObjectParameterInfo.NULTERMINATE, ObjectParameterInfo.CLEAR, }; @Test public void testCache() { for (int i = 0; i < 256; i++) { for (ObjectParameterInfo.ObjectType objectType : EnumSet.allOf(ObjectParameterInfo.ObjectType.class)) { for (ObjectParameterInfo.ComponentType componentType : EnumSet.allOf(ObjectParameterInfo.ComponentType.class)) { int ioflags = 0; for (int f : possibleFlags) { ioflags |= f; ObjectParameterInfo info1 = ObjectParameterInfo.create(i, objectType, componentType, ioflags); ObjectParameterInfo info2 = ObjectParameterInfo.create(i, objectType, componentType, ioflags); assertEquals(i, info1.getParameterIndex()); assertEquals(i, info2.getParameterIndex()); assertEquals(ioflags, info1.ioflags()); assertEquals(ioflags, info2.ioflags()); assertSame(info1, info2); } } } } } } jffi-1.2.7/src/test/java/com/kenai/jffi/PlatformTest.java000066400000000000000000000015351247047424400232140ustar00rootroot00000000000000 package com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * Tests the Platform class */ public class PlatformTest { public PlatformTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void isSupported() { // This should never fail assertTrue("isSupported failed", Platform.getPlatform().isSupported()); } }jffi-1.2.7/src/test/java/com/kenai/jffi/StructTest.java000066400000000000000000000243561247047424400227220ustar00rootroot00000000000000 package com.kenai.jffi; import com.kenai.jffi.UnitHelper.Address; import java.nio.ByteBuffer; import java.nio.ByteOrder; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * Tests C struct parameters and return values using pass/return by value. */ public class StructTest { public StructTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} // // struct { char c; }; // @Test public void s8UsingForeign() throws Throwable { Foreign foreign = Foreign.getInstance(); long sint8 = foreign.lookupBuiltinType(Foreign.TYPE_SINT8); long struct = foreign.newStruct(new long[] { sint8 }, false); assertEquals("Incorrect size", 1, foreign.getTypeSize(struct)); assertEquals("Incorrect alignment", 1, foreign.getTypeAlign(struct)); } @Test public void s8UsingStruct() throws Throwable { Struct s8 = new Struct(Type.SINT8); assertEquals("Incorrect size", 1, s8.size()); assertEquals("Incorrect alignment", 1, s8.alignment()); } // // struct { char c; int i; }; // @Test public void s8s32UsingForeign() throws Throwable { Foreign foreign = Foreign.getInstance(); long sint8 = foreign.lookupBuiltinType(Foreign.TYPE_SINT8); long sint32 = foreign.lookupBuiltinType(Foreign.TYPE_SINT32); long struct = foreign.newStruct(new long[] { sint8, sint32 }, false); assertEquals("Incorrect size", 8, foreign.getTypeSize(struct)); assertEquals("Incorrect alignment", 4, foreign.getTypeAlign(struct)); } @Test public void s8s32UsingStruct() throws Throwable { Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); assertEquals("Incorrect size", 8, s8s32.size()); assertEquals("Incorrect alignment", 4, s8s32.alignment()); } @Test public void s8s32ReturnWithDefaultBuffer() throws Throwable { Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Address sym = UnitHelper.findSymbol("struct_return_s8s32"); Function f = new Function(sym.address, s8s32/*, new Type[0]*/); byte[] returnBuffer = Invoker.getInstance().invokeStruct(f, new HeapInvocationBuffer(f)); ByteBuffer buf = ByteBuffer.wrap(returnBuffer).order(ByteOrder.nativeOrder()); assertEquals("Wrong s8 value", (byte) 0x7f, buf.get(0)); assertEquals("Wrong s32 value", 0x12345678, buf.getInt(4)); } @Test public void s8s32ReturnWithProvidedBuffer() throws Throwable { Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Address sym = UnitHelper.findSymbol("struct_return_s8s32"); Function f = new Function(sym.address, s8s32/*, new Type[0]*/); byte[] returnBuffer = new byte[s8s32.size()]; Invoker.getInstance().invokeStruct(f, new HeapInvocationBuffer(f), returnBuffer, 0); ByteBuffer buf = ByteBuffer.wrap(returnBuffer).order(ByteOrder.nativeOrder()); assertEquals("Wrong s8 value", (byte) 0x7f, buf.get(0)); assertEquals("Wrong s32 value", 0x12345678, buf.getInt(4)); } @Test public void s8s32ReturnWithProvidedBufferAndOffset() throws Throwable { Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Address sym = UnitHelper.findSymbol("struct_return_s8s32"); Function f = new Function(sym.address, s8s32, new Type[0]); int adj = 8; byte[] returnBuffer = new byte[adj + s8s32.size()]; Invoker.getInstance().invokeStruct(f, new HeapInvocationBuffer(f), returnBuffer, adj); ByteBuffer buf = ByteBuffer.wrap(returnBuffer, adj, s8s32.size()).slice().order(ByteOrder.nativeOrder()); assertEquals("Wrong s8 value", (byte) 0x7f, buf.get(0)); assertEquals("Wrong s32 value", 0x12345678, buf.getInt(4)); } @Test public void structS8S32ParameterFromArray() throws Throwable { Address sym_s8 = UnitHelper.findSymbol("struct_s8s32_get_s8"); Address sym_s32 = UnitHelper.findSymbol("struct_s8s32_get_s32"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function get_s8 = new Function(sym_s8.address, Type.SINT32, s8s32 ); Function get_s32 = new Function(sym_s32.address, Type.SINT32, s8s32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(get_s8); ByteBuffer buf = ByteBuffer.allocate(s8s32.size()).order(ByteOrder.nativeOrder()); buf.put(0, (byte) 0x12); buf.putInt(4, 0x87654321); paramBuffer.putStruct(buf.array(), buf.arrayOffset()); assertEquals("Wrong s8 value", 0x12, Invoker.getInstance().invokeInt(get_s8, paramBuffer)); assertEquals("Wrong s32 value", 0x87654321, Invoker.getInstance().invokeInt(get_s32, paramBuffer)); } @Test public void structS8S32ParameterFromPointer() throws Throwable { Address sym_s8 = UnitHelper.findSymbol("struct_s8s32_get_s8"); Address sym_s32 = UnitHelper.findSymbol("struct_s8s32_get_s32"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function get_s8 = new Function(sym_s8.address, Type.SINT32, s8s32); Function get_s32 = new Function(sym_s32.address, Type.SINT32, s8s32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(get_s8); long struct = MemoryIO.getInstance().allocateMemory(s8s32.size(), true); MemoryIO.getInstance().putByte(struct, (byte) 0x12); MemoryIO.getInstance().putInt(struct + 4, 0x87654321); paramBuffer.putStruct(struct); assertEquals("Wrong s8 value", 0x12, Invoker.getInstance().invokeInt(get_s8, paramBuffer)); assertEquals("Wrong s32 value", 0x87654321, Invoker.getInstance().invokeInt(get_s32, paramBuffer)); } @Test public void structS8S32ParameterFromArrayAndS32() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_s32_ret_s32"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function function = new Function(sym.address, Type.SINT32, s8s32, Type.SINT32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); ByteBuffer buf = ByteBuffer.allocate(s8s32.size()).order(ByteOrder.nativeOrder()); buf.put(0, (byte) 0x12); buf.putInt(4, 0x87654321); paramBuffer.putStruct(buf.array(), buf.arrayOffset()); paramBuffer.putInt(0xdeadbeef); int retval = Invoker.getInstance().invokeInt(function, paramBuffer); assertEquals("Wrong s32 param value", (int) 0xdeadbeef, retval); } @Test public void structS8S32ParameterFromPointerAndS32() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_s32_ret_s32"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function function = new Function(sym.address, Type.SINT32, s8s32, Type.SINT32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); long struct = MemoryIO.getInstance().allocateMemory(s8s32.size(), true); MemoryIO.getInstance().putByte(struct, (byte) 0x12); MemoryIO.getInstance().putInt(struct + 4, 0x87654321); paramBuffer.putStruct(struct); // Add a following int32 param and ensure it is passed paramBuffer.putInt(0xdeadbeef); int retval = Invoker.getInstance().invokeInt(function, paramBuffer); assertEquals("Wrong s32 param value", (int) 0xdeadbeef, retval); } @Test public void structS8S32ParameterFromArrayAndS64() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_s64_ret_s64"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function function = new Function(sym.address, Type.SINT64, s8s32, Type.SINT64); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); ByteBuffer buf = ByteBuffer.allocate(s8s32.size()).order(ByteOrder.nativeOrder()); buf.put(0, (byte) 0x12); buf.putInt(4, 0x87654321); paramBuffer.putStruct(buf.array(), buf.arrayOffset()); paramBuffer.putLong(0xdeadbeef); long retval = Invoker.getInstance().invokeLong(function, paramBuffer); assertEquals("Wrong s64 param value", 0xdeadbeef, retval); } @Test public void structS8S32ParameterFromPointerAndS64() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_s64_ret_s64"); Struct s8s32 = new Struct(new Type[] { Type.SINT8, Type.SINT32 }); Function function = new Function(sym.address, Type.SINT64, s8s32, Type.SINT64); long struct = MemoryIO.getInstance().allocateMemory(s8s32.size(), true); MemoryIO.getInstance().putByte(struct, (byte) 0x12); MemoryIO.getInstance().putInt(struct + 4, 0x87654321); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); paramBuffer.putStruct(struct); // Add a following int64 param and ensure it is passed paramBuffer.putLong(0xdeadbeef); long retval = Invoker.getInstance().invokeLong(function, paramBuffer); assertEquals("Wrong s64 param value", 0xdeadbeef, retval); } @Test public void s8s32_set() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_set"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function function = new Function(sym.address, s8s32, Type.SINT8, Type.SINT32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); paramBuffer.putByte((byte) 0x12); paramBuffer.putInt(0x87654321); byte[] returnBuffer = Invoker.getInstance().invokeStruct(function, paramBuffer); ByteBuffer buf = ByteBuffer.wrap(returnBuffer).order(ByteOrder.nativeOrder()); assertEquals("Wrong s8 value", (byte) 0x12, buf.get(0)); assertEquals("Wrong s32 value", 0x87654321, buf.getInt(4)); } } jffi-1.2.7/src/test/java/com/kenai/jffi/TypeTest.java000066400000000000000000000022721247047424400223500ustar00rootroot00000000000000/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * * @author wayne */ public class TypeTest { public TypeTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void lookupBuiltinType() throws Throwable { Foreign foreign = Foreign.getInstance(); long handle = foreign.lookupBuiltinType(Foreign.TYPE_SINT8); assertEquals("Incorrect type", Type.SINT8.type(), foreign.getTypeType(handle)); assertEquals("Incorrect size", 1, foreign.getTypeSize(handle)); assertEquals("Incorrect alignment", 1, foreign.getTypeAlign(handle)); } }jffi-1.2.7/src/test/java/com/kenai/jffi/UnitHelper.java000066400000000000000000000553711247047424400226560ustar00rootroot00000000000000 package com.kenai.jffi; import java.io.File; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.math.BigDecimal; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class UnitHelper { public enum InvokerType { Default, FastInt, FastLong, FastNumeric, PointerArray } public static final class Address extends java.lang.Number { public final int SIZE = Platform.getPlatform().addressSize(); public final long MASK = Platform.getPlatform().addressMask(); public final long address; public Address(long address) { this.address = address & MASK; } public Address(Closure.Handle closure) { this(closure.getAddress()); } @Override public int intValue() { return (int) address; } @Override public long longValue() { return address; } @Override public float floatValue() { return (float) address; } @Override public double doubleValue() { return (double) address; } } public static final String getCLibraryName() { switch (Platform.getPlatform().getOS()) { case LINUX: return "libc.so.6"; case DARWIN: return "libc.dylib"; case WINDOWS: return "msvcrt.dll"; case AIX: if (Platform.getPlatform().addressSize() == 32){ return "libc.a(shr.o)"; } else { return "libc.a(shr_64.o)"; } default: return "libc.so"; } } public static T loadTestLibrary(Class interfaceClass) { return loadTestLibrary(interfaceClass, InvokerType.Default); } public static T loadTestLibrary(Class interfaceClass, InvokerType invokerType) { String name = Platform.getPlatform().mapLibraryName("test"); return loadLibrary(new File("build", name).getAbsolutePath(), interfaceClass, invokerType); } /** * Creates a new InvocationHandler mapping methods in the interfaceClass * to functions in the native library. * @param the type of interfaceClass * @param libraryName the native library to load * @param interfaceClass the interface that contains the native method description * @return a new instance of interfaceClass that can be used to call * functions in the native library. */ public static T loadLibrary(String name, Class interfaceClass, InvokerType invokerType) { Library lib = Library.getCachedInstance(name, Library.LAZY); if (lib == null) { throw new UnsatisfiedLinkError(String.format("Could not load '%s': %s", name, Library.getLastError())); } return interfaceClass.cast(Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{ interfaceClass }, new NativeInvocationHandler(lib, invokerType))); } private static final class LibraryHolder { static final Library libtest = Library.getCachedInstance( new File("build", Platform.getPlatform().mapLibraryName("test")).getAbsolutePath(), Library.LAZY); } public static Address findSymbol(String name) { final long address = LibraryHolder.libtest.getSymbolAddress(name); if (address == 0L) { throw new UnsatisfiedLinkError("Could not locate symbol '" + name + "'"); } return new Address(address); } private static final class NativeInvocationHandler implements InvocationHandler { private final ConcurrentMap invokers = new ConcurrentHashMap(); private final Library library; private final InvokerType invokerType; public NativeInvocationHandler(Library library, InvokerType invokerType) { this.library = library; this.invokerType = invokerType; } public Object invoke(Object self, Method method, Object[] argArray) throws Throwable { return getMethodInvoker(method).invoke(argArray); } /** * Gets the {@link Invoker} for a method. * * @param method the method defined in the interface class * @return the Invoker to use to invoke the native function */ private final MethodInvoker getMethodInvoker(Method method) { MethodInvoker invoker = invokers.get(method); if (invoker != null) { return invoker; } invokers.put(method, invoker = createInvoker(library, method, invokerType)); return invoker; } } private static final MethodInvoker createInvoker(Library library, Method method, InvokerType invokerType) { Class returnType = method.getReturnType(); Class[] parameterTypes = method.getParameterTypes(); Type ffiReturnType = convertClassToFFI(returnType); Type[] ffiParameterTypes = new Type[parameterTypes.length]; for (int i = 0; i < ffiParameterTypes.length; ++i) { ffiParameterTypes[i] = convertClassToFFI(parameterTypes[i]); } final long address = library.getSymbolAddress(method.getName()); if (address == 0) { throw new UnsatisfiedLinkError(String.format("Could not locate '%s': %s", method.getName(), Library.getLastError())); } Function function = new Function(address, ffiReturnType, ffiParameterTypes); switch (invokerType) { case FastInt: return new FastIntMethodInvoker(library, function, returnType, parameterTypes); case FastLong: return new FastLongMethodInvoker(library, function, returnType, parameterTypes); case FastNumeric: return new FastNumericMethodInvoker(library, function, returnType, parameterTypes); case PointerArray: return new PointerArrayMethodInvoker(library, function, returnType, parameterTypes); case Default: return new DefaultMethodInvoker(library, function, returnType, parameterTypes); default: throw new RuntimeException("Unsupported InvokerType: " + invokerType); } } private static Type convertClassToFFI(Class type) { if (type == void.class || type == Void.class) { return Type.VOID; } else if (type == byte.class || type == Byte.class) { return Type.SINT8; } else if (type == short.class || type == Short.class) { return Type.SINT16; } else if (type == int.class || type == Integer.class) { return Type.SINT32; } else if (type == long.class || type == Long.class) { return Type.SINT64; } else if (type == float.class || type == Float.class) { return Type.FLOAT; } else if (type == double.class || type == Double.class) { return Type.DOUBLE; } else if (BigDecimal.class.isAssignableFrom(type)) { return Type.LONGDOUBLE; } else if (Address.class.isAssignableFrom(type)) { return Type.POINTER; } else { throw new IllegalArgumentException("Unknown type: " + type); } } private static interface MethodInvoker { public Object invoke(Object[] args); } private static final class DefaultMethodInvoker implements MethodInvoker { private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public DefaultMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } public Object invoke(Object[] args) { HeapInvocationBuffer buffer = new HeapInvocationBuffer(function); for (int i = 0; i < args.length; ++i) { if (parameterTypes[i] == byte.class || parameterTypes[i] == Byte.class) { buffer.putByte(((Number) args[i]).intValue()); } else if (parameterTypes[i] == short.class || parameterTypes[i] == Short.class) { buffer.putShort(((Number) args[i]).intValue()); } else if (parameterTypes[i] == int.class || parameterTypes[i] == Integer.class) { buffer.putInt(((Number) args[i]).intValue()); } else if (parameterTypes[i] == long.class || parameterTypes[i] == Long.class) { buffer.putLong(((Number) args[i]).longValue()); } else if (parameterTypes[i] == float.class || parameterTypes[i] == Float.class) { buffer.putFloat(((Number) args[i]).floatValue()); } else if (parameterTypes[i] == double.class || parameterTypes[i] == Double.class) { buffer.putDouble(((Number) args[i]).doubleValue()); } else if (BigDecimal.class.isAssignableFrom(parameterTypes[i])) { buffer.putLongDouble(BigDecimal.class.cast(args[i])); } else if (Address.class.isAssignableFrom(parameterTypes[i])) { buffer.putAddress(((Address) args[i]).address); } else { throw new RuntimeException("Unknown parameter type: " + parameterTypes[i]); } } Invoker invoker = Invoker.getInstance(); if (returnType == void.class || returnType == Void.class) { invoker.invokeInt(function, buffer); return null; } else if (returnType == byte.class || returnType == Byte.class) { return Byte.valueOf((byte) invoker.invokeInt(function, buffer)); } else if (returnType == short.class || returnType == Short.class) { return Short.valueOf((short) invoker.invokeInt(function, buffer)); } else if (returnType == int.class || returnType == Integer.class) { return Integer.valueOf(invoker.invokeInt(function, buffer)); } else if (returnType == long.class || returnType == Long.class) { return Long.valueOf(invoker.invokeLong(function, buffer)); } else if (returnType == float.class || returnType == Float.class) { return Float.valueOf(invoker.invokeFloat(function, buffer)); } else if (returnType == double.class || returnType == Double.class) { return Double.valueOf(invoker.invokeDouble(function, buffer)); } else if (BigDecimal.class.isAssignableFrom(returnType)) { return invoker.invokeBigDecimal(function, buffer); } else if (Address.class.isAssignableFrom(returnType)) { return new Address(invoker.invokeAddress(function, buffer)); } throw new RuntimeException("Unknown return type: " + returnType); } } private static final Number convertResult(Class returnType, Number result) { if (returnType == void.class || returnType == Void.class) { return null; } else if (returnType == byte.class || returnType == Byte.class) { return result.byteValue(); } else if (returnType == short.class || returnType == Short.class) { return result.shortValue(); } else if (returnType == int.class || returnType == Integer.class) { return result.intValue(); } else if (returnType == long.class || returnType == Long.class) { return result.longValue(); } else if (returnType == float.class || returnType == Float.class) { return Float.intBitsToFloat(result.intValue()); } else if (returnType == double.class || returnType == Double.class) { return Double.longBitsToDouble(result.longValue()); } else if (Address.class.isAssignableFrom(returnType)) { return new Address(result.longValue()); } throw new RuntimeException("Unknown return type: " + returnType); } private static final class FastIntMethodInvoker implements MethodInvoker { private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public FastIntMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } private static final boolean isFloat(Class c) { return Float.class.isAssignableFrom(c) || float.class == c; } private static final int i(Object value) { return value instanceof Float ? Float.floatToRawIntBits(((Float) value).floatValue()) : ((Number) value).intValue(); } public Object invoke(Object[] args) { final int result; switch (args.length) { case 0: result = Invoker.getInstance().invokeI0(function.getCallContext(), function.getFunctionAddress()); break; case 1: result = Invoker.getInstance().invokeI1(function.getCallContext(), function.getFunctionAddress(), i(args[0])); break; case 2: result = Invoker.getInstance().invokeI2(function.getCallContext(), function.getFunctionAddress(), ((Number) args[0]).intValue(), ((Number) args[1]).intValue()); break; case 3: result = Invoker.getInstance().invokeI3(function.getCallContext(), function.getFunctionAddress(), ((Number) args[0]).intValue(), ((Number) args[1]).intValue(), ((Number) args[2]).intValue()); break; default: throw new IndexOutOfBoundsException("fast-int invoker limited to 3 parameters"); } return convertResult(returnType, result); } } private static final class FastLongMethodInvoker implements MethodInvoker { private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public FastLongMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } public Object invoke(Object[] args) { final long result; switch (args.length) { case 0: result = Invoker.getInstance().invokeL0(function.getCallContext(), function.getFunctionAddress()); break; case 1: result = Invoker.getInstance().invokeL1(function.getCallContext(), function.getFunctionAddress(), ((Number) args[0]).longValue()); break; case 2: result = Invoker.getInstance().invokeL2(function.getCallContext(), function.getFunctionAddress(), ((Number) args[0]).longValue(), ((Number) args[1]).longValue()); break; case 3: result = Invoker.getInstance().invokeL3(function.getCallContext(), function.getFunctionAddress(), ((Number) args[0]).longValue(), ((Number) args[1]).longValue(), ((Number) args[2]).longValue()); break; default: throw new IndexOutOfBoundsException("fast-long invoker limited to 3 parameters"); } return convertResult(returnType, result); } } private static final class FastNumericMethodInvoker implements MethodInvoker { private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public FastNumericMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } public Object invoke(Object[] args) { final long result; switch (args.length) { case 0: result = Invoker.getInstance().invokeN0(function.getCallContext(), function.getFunctionAddress()); break; case 1: result = Invoker.getInstance().invokeN1(function.getCallContext(), function.getFunctionAddress(), l(args[0])); break; case 2: result = Invoker.getInstance().invokeN2(function.getCallContext(), function.getFunctionAddress(), l(args[0]), l(args[1])); break; case 3: result = Invoker.getInstance().invokeN3(function.getCallContext(), function.getFunctionAddress(), l(args[0]), l(args[1]), l(args[1])); break; default: throw new IndexOutOfBoundsException("fast-numeric invoker limited to 3 parameters"); } return convertResult(returnType, result); } private static final long l(Object arg) { if (arg instanceof Float) { return Float.floatToRawIntBits(((Float) arg).floatValue()); } else if (arg instanceof Double) { return Double.doubleToRawLongBits(((Double) arg).doubleValue()); } else { return ((Number) arg).longValue(); } } } private static final class PointerArrayMethodInvoker implements MethodInvoker { private static final MemoryIO Memory = MemoryIO.getInstance(); private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public PointerArrayMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } private static final class MemoryHolder { private final long address; public MemoryHolder(long address) { this.address = address; } @Override protected void finalize() throws Throwable { MemoryIO.getInstance().freeMemory(address); } } private long getNativeLongReturnValue(long address) { return Platform.getPlatform().longSize() == 32 ? Memory.getInt(address) : Memory.getLong(address); } public Object invoke(Object[] args) { MemoryHolder[] memoryHolders = new MemoryHolder[function.getParameterCount()]; long[] parameterAddresses = new long[function.getParameterCount()]; for (int i = 0; i < parameterAddresses.length; ++i) { // Allocate 8 bytes; enough to store long long and double parameterAddresses[i] = Memory.allocateMemory(8, true); memoryHolders[i] = new MemoryHolder(parameterAddresses[i]); } for (int i = 0; i < args.length; ++i) { if (parameterTypes[i] == byte.class || parameterTypes[i] == Byte.class) { Memory.putByte(parameterAddresses[i], ((Number) args[i]).byteValue()); } else if (parameterTypes[i] == short.class || parameterTypes[i] == Short.class) { Memory.putShort(parameterAddresses[i], ((Number) args[i]).shortValue()); } else if (parameterTypes[i] == int.class || parameterTypes[i] == Integer.class) { Memory.putInt(parameterAddresses[i], ((Number) args[i]).intValue()); } else if (parameterTypes[i] == long.class || parameterTypes[i] == Long.class) { Memory.putLong(parameterAddresses[i], ((Number) args[i]).longValue()); } else if (parameterTypes[i] == float.class || parameterTypes[i] == Float.class) { Memory.putFloat(parameterAddresses[i], ((Number) args[i]).floatValue()); } else if (parameterTypes[i] == double.class || parameterTypes[i] == Double.class) { Memory.putDouble(parameterAddresses[i], ((Number) args[i]).doubleValue()); } else if (Address.class.isAssignableFrom(parameterTypes[i])) { Memory.putAddress(parameterAddresses[i], ((Address) args[i]).address); } else { throw new RuntimeException("Unknown parameter type: " + parameterTypes[i]); } } long returnBuffer = Memory.allocateMemory(8, true); try { Invoker.getInstance().invoke(function, returnBuffer, parameterAddresses); if (returnType == void.class || returnType == Void.class) { return null; } else if (returnType == byte.class || returnType == Byte.class) { return (byte) getNativeLongReturnValue(returnBuffer); } else if (returnType == short.class || returnType == Short.class) { return (short) getNativeLongReturnValue(returnBuffer); } else if (returnType == int.class || returnType == Integer.class) { return (int) getNativeLongReturnValue(returnBuffer); } else if (returnType == long.class || returnType == Long.class) { return Memory.getLong(returnBuffer); } else if (returnType == float.class || returnType == Float.class) { return Memory.getFloat(returnBuffer); } else if (returnType == double.class || returnType == Double.class) { return Memory.getDouble(returnBuffer); } else if (Address.class.isAssignableFrom(returnType)) { return new Address(Memory.getAddress(returnBuffer)); } throw new RuntimeException("Unknown return type: " + returnType); } finally { Memory.freeMemory(returnBuffer); } } } } jffi-1.2.7/version.xml000066400000000000000000000015621247047424400146620ustar00rootroot00000000000000 package com.kenai.jffi; public final class Version { private Version() {} public static final int MAJOR = ${jffi.version.major}; public static final int MINOR = ${jffi.version.minor}; public static final int MICRO = ${jffi.version.micro}; }