License
=======
-The Mono project uses the MIT X11, GNU LGPL version 2 and the Apache
-License 2.0. We also imported some Microsoft code licensed under the
-open source Microsoft Public License.
+The Mono runtime, compilers, and tools and most of the class libraries
+are licensed under the MIT license. But include some bits of code
+licensed under different licenses. The exact list is [available here] (https://github.com/mono/mono/blob/master/LICENSE).
Different parts of Mono use different licenses. The actual details of
which licenses are used for which parts are detailed on the LICENSE
file in this directory.
-When contributing code, make sure that your contribution falls under
-the appropriate license. For example, contributions to code licensed
-under MIT/X11 code, should be MIT/X11 code.
-
-The runtime (`mono/...`) is a special case. The code is dual-licensed
-by Xamarin under both the GNU LGPL v2 license and is also available
-under commercial terms. For the runtime, you should either sign an
-agreement that grants Xamarin the rights to relicense your code under
-other licenses other than the LGPL v2 or your contribution must be
-made as an MIT/X11 license which grants us the same rights, but
-involves no paperwork. For the latter case, please specify on your
-commit(s) that you are licensing the changes under MIT/X11.
-
-For other parts of the project that are dual-licensed, please state
-on your commit(s) what license you are contributing the changes under.
+CLA
+=======
+
+Contributions are now taken under the [.NET Foundation CLA] (https://cla2.dotnetfoundation.org/).
Testing
=======
-
-The Mono runtime is licensed under the terms of the GNU
-Library General Public License, version 2.
-
-The eglib directory is licensed under the terms of the MIT
-X11 license and is a drop-in replacement for Mono's use of
-glib 2.0 (which was LGPL).
-
-The Boehm licensing information is in the libgc directory
-
-The SGen Garbage Collector is under the terms of the MIT X11
-license
-
-The class libraries under mono/mcs are unless otherwise stated
-under the MIT X11 license.
-
-Open source Microsoft code is licensed under the original terms
-which is either MS-PL for older components, or dual licensed
-MS-PL/Apache2 licensed.
-
- GNU LIBRARY GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the library GPL. It is
- numbered 2 because it goes with version 2 of the ordinary GPL.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Library General Public License, applies to some
-specially designated Free Software Foundation software, and to any
-other libraries whose authors decide to use it. You can use it for
-your libraries, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if
-you distribute copies of the library, or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link a program with the library, you must provide
-complete object files to the recipients so that they can relink them
-with the library, after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- Our method of protecting your rights has two steps: (1) copyright
-the library, and (2) offer you this license which gives you legal
-permission to copy, distribute and/or modify the library.
-
- Also, for each distributor's protection, we want to make certain
-that everyone understands that there is no warranty for this free
-library. If the library is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original
-version, so that any problems introduced by others will not reflect on
-the original authors' reputations.
-\f
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that companies distributing free
-software will individually obtain patent licenses, thus in effect
-transforming the program into proprietary software. To prevent this,
-we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
- Most GNU software, including some libraries, is covered by the ordinary
-GNU General Public License, which was designed for utility programs. This
-license, the GNU Library General Public License, applies to certain
-designated libraries. This license is quite different from the ordinary
-one; be sure to read it in full, and don't assume that anything in it is
-the same as in the ordinary license.
-
- The reason we have a separate public license for some libraries is that
-they blur the distinction we usually make between modifying or adding to a
-program and simply using it. Linking a program with a library, without
-changing the library, is in some sense simply using the library, and is
-analogous to running a utility program or application program. However, in
-a textual and legal sense, the linked executable is a combined work, a
-derivative of the original library, and the ordinary General Public License
-treats it as such.
-
- Because of this blurred distinction, using the ordinary General
-Public License for libraries did not effectively promote software
-sharing, because most developers did not use the libraries. We
-concluded that weaker conditions might promote sharing better.
-
- However, unrestricted linking of non-free programs would deprive the
-users of those programs of all benefit from the free status of the
-libraries themselves. This Library General Public License is intended to
-permit developers of non-free programs to use free libraries, while
-preserving your freedom as a user of such programs to change the free
-libraries that are incorporated in them. (We have not seen how to achieve
-this as regards changes in header files, but we have achieved it as regards
-changes in the actual functions of the Library.) The hope is that this
-will lead to faster development of free libraries.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, while the latter only
-works together with the library.
-
- Note that it is possible for a library to be covered by the ordinary
-General Public License rather than by this special one.
-\f
- GNU LIBRARY GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library which
-contains a notice placed by the copyright holder or other authorized
-party saying it may be distributed under the terms of this Library
-General Public License (also called "this License"). Each licensee is
-addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-\f
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-\f
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-\f
- 6. As an exception to the Sections above, you may also compile or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- c) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- d) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the source code distributed need not include anything that is normally
-distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-\f
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-\f
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Library General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-\f
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-\f
- Appendix: How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
+See LICENSE file in the project root for full license information.
\ No newline at end of file
-Mono is made up of many pieces of code, all of them open source, but
-different pieces of Mono use different licensing terms.
+In general, the runtime and its class libraries are licensed under the
+terms of the MIT license, and some third party code is licensed under
+the 3-clause BSD license. See the file "PATENTS.TXT" for Microsoft's
+patent grant on the Mono codebase.
-For comments, corrections and updates, please contact mono@xamarin.com
+The Mono distribution does include a handful of pieces of code that
+are used during the build system and are covered under different
+licenses, those include:
-* Dual Licensing
+Build Time Code
+===============
- Parts of Mono are dual licensed, they are available to the
- public in GPL or LGPL forms, but we also offer those pieces
- under commercial terms from Xamarin for the cases where the
- GPL and the LGPL are not suitable.
+This is code that is used at build time, or during the maintenance of
+Mono itself, and does not end up in the redistributable part of Mono:
- We have tried to pick the licenses that will maximize adoption
- of Mono, so we tend to use the MIT X11 or LGPL liceses.
+* gettext
- Contributions to dual-licensed module require that the author
- contributes the code under the terms of the MIT X11 code, or
- to sign an agreement that allows Novell to redistribute the
- code under other licenses.
+ m4 source files used to probe features at build time: GPL
- Contributions for other modules should be under the same license
- terms as the rest of the module, or under MIT X11 terms.
+* Benchmark Source Files
- For the actual license links in the Mono distribution see the
- bottom of this file.
+ Logic.cs and zipmark.cs are GPL source files.
- If you need further information, please contact mono@xamarin.com
+* mono/docs/HtmlAgilityPack
-* The Modules
+ MS-PL licensed
-** mono/mono: the Mono VM
+* mcs/jay: 4-clause BSD licensed
- This code is dual licensed under the LGPL or commercial licenses.
+* mcs/nunit24: MS-PL
- The LGPL ensures that Mono can be used in most scenarios, but
- gives Xamarin the flexibility to relicense the code for
- embedded systems, static linking or commercial settings where
- the LGPL can not be used.
+* mcs/class/I18N/mklist.sh, tools/cvt.sh: GNU GPLv2
- We consider non-LGPL use instances where you use this on an
- embedded system where the end user is not able to upgrade the
- Mono VM or Moonlight installation or distribution that is part
- of your product (Section 6 and 7), you would have to obtain a
- commercial license from Xamarin (consider software burned into
- a ROM, systems where end users would not be able to upgrade,
- an embedded console, a game console that imposes limitations
- on the distribution and access to the code, a phone platform
- that prevents end users from upgrading Moonlight).
-
- Contact mono@xamarin.com for details on obtaining the Mono
- runtime under other terms.
+Runtime Code
+============
-** mono/support: MonoPosixHelper and support code
+The following code is linked with the final Mono runtime, the libmono
+embeddable runtime:
- This code is dual licensed under the LGPL or commercial licenses, with
- the same guidelines as mono/mono code.
+* support/minizip: BSD license.
- The ZLib files are included under a "new BSD"-style license.
+* mono/utils/memcheck.h: BSD license, used on debug builds that use Valgrind.
-** mono/eglib: Mono's X11 glib implementation
+* mono/utils/freebsd-dwarf.h, freebsd-elf_common.h, freebsd-elf64.h freebsd-elf32.h: BSD license.
- This is a minimal subset of glib that is to be licensed under
- the terms of the MIT X11, this means that this code can be
- used for any purposes by anyone.
+* mono/utils/bsearch.c: BSD license.
-** mono/arch/*/XXX-codegen.h
+* mono/io-layer/wapi_glob.h, wapi_glob.c: BSD license
- This are C macros that are useful when generating native
- code on various platforms. This code is MIT X11 licensed.
+Class Library code
+==================
-** mcs/mcs, mcs/gmcs
+These are class libraries that can be loaded by your process:
- The C# Compilers (1.0 and 2.0)
+* mcs/class/RabbitMQ.Client: dual licensed in Apache v2, and Mozilla Public License 1.1
- These compilers are dual licensed under the GPL and MIT X11
- license terms.
+* mcs/class/Compat.ICSharpCode.SharpZipLib and
+ mcs/class/ICSharpCode.SharpZipLib are GPL with class-path exception.
+ Originates with the SharpDevelop project.
-** tests
+* mcs/class/System.Core/System/TimeZoneInfo.Android.cs
- Unless explicitly stated, the tests are under the MIT X11 license.
+ This is a port of Apache 2.0-licensed Android code, and thus is
+ licensed under the Apache 2.0 license
-** mcs/class
+ http://www.apache.org/licenses/LICENSE-2.0
- The class libraries developed by the Mono team are licensed
- under the MIT X11 terms.
+API Documentation
+=================
- In addition to the class libraries developed by the Mono team,
- there are a number of class libraries that we bundle as part
- of the distribution that were integrated from third-parties or
- that contain code that was originally licensed under different
- terms, these are:
+The API documentation is licensed under the terms of the Creative
+Commons Attribution 4.0 International Public License
- ByteFX.Data: LGPL
- Npgsql: LGPL
+The Licenses
+============
- FirebirdSql.Data.Firebird: Firebird public license.
- See: mcs/class/FirebirdSql.Data.Firebird/license.txt
+ These are the licenses used in Mono, the files are located:
- ICSharpCode.SharpZipLib, GPL with exceptions.
- See: mcs/class/ICSharpCode.SharpZipLib/README
+### MIT X11 License
-** mcs/class/System.Core/System/TimeZoneInfo.Android.cs
+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:
- This is a port of Apache 2.0-licensed Android code, and thus is
- licensed under the Apache 2.0 license:
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
- http://www.apache.org/licenses/LICENSE-2.0
+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.
-
-** mcs/tools
- These are licensed under the MIT X11 license, except where the
- GPL is explicitly used.
+### Mozilla.MPL
-** mcs/jay
+ MOZILLA PUBLIC LICENSE
+ Version 1.1
- This is a port of Berkeley yacc, so it is available under the BSD
- license. See the license in the individual C files for details.
+ ---------------
-** mono/man
+1. Definitions.
- Manual pages and Mono documentation are covered by the MIT X11 license.
+ 1.0.1. "Commercial Use" means distribution or otherwise making the
+ Covered Code available to a third party.
-* samples
+ 1.1. "Contributor" means each entity that creates or contributes to
+ the creation of Modifications.
- The code in the "samples" directory is released under the MIT X11 license.
+ 1.2. "Contributor Version" means the combination of the Original
+ Code, prior Modifications used by a Contributor, and the Modifications
+ made by that particular Contributor.
-* The Licenses
+ 1.3. "Covered Code" means the Original Code or Modifications or the
+ combination of the Original Code and Modifications, in each case
+ including portions thereof.
- These are the licenses used in Mono, the files are located:
+ 1.4. "Electronic Distribution Mechanism" means a mechanism generally
+ accepted in the software development community for the electronic
+ transfer of data.
+
+ 1.5. "Executable" means Covered Code in any form other than Source
+ Code.
+
+ 1.6. "Initial Developer" means the individual or entity identified
+ as the Initial Developer in the Source Code notice required by Exhibit
+ A.
+
+ 1.7. "Larger Work" means a work which combines Covered Code or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.8. "License" means this document.
+
+ 1.8.1. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means any addition to or deletion from the
+ substance or structure of either the Original Code or any previous
+ Modifications. When Covered Code is released as a series of files, a
+ Modification is:
+ A. Any addition to or deletion from the contents of a file
+ containing Original Code or previous Modifications.
+
+ B. Any new file that contains any part of the Original Code or
+ previous Modifications.
+
+ 1.10. "Original Code" means Source Code of computer software code
+ which is described in the Source Code notice required by Exhibit A as
+ Original Code, and which, at the time of its release under this
+ License is not already Covered Code governed by this License.
+
+ 1.10.1. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.11. "Source Code" means the preferred form of the Covered Code for
+ making modifications to it, including all modules it contains, plus
+ any associated interface definition files, scripts used to control
+ compilation and installation of an Executable, or source code
+ differential comparisons against either the Original Code or another
+ well known, available Covered Code of the Contributor's choice. The
+ Source Code can be in a compressed or archival form, provided the
+ appropriate decompression or de-archiving software is widely available
+ for no charge.
+
+ 1.12. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of, this
+ License or a future version of this License issued under Section 6.1.
+ For legal entities, "You" includes any entity which controls, is
+ controlled by, or is under common control with You. For purposes of
+ this definition, "control" means (a) the power, direct or indirect,
+ to cause the direction or management of such entity, whether by
+ contract or otherwise, or (b) ownership of more than fifty percent
+ (50%) of the outstanding shares or beneficial ownership of such
+ entity.
+
+2. Source Code License.
+
+ 2.1. The Initial Developer Grant.
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property
+ claims:
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Code (or portions thereof) with or without Modifications, and/or
+ as part of a Larger Work; and
+
+ (b) under Patents Claims infringed by the making, using or
+ selling of Original Code, to make, have made, use, practice,
+ sell, and offer for sale, and/or otherwise dispose of the
+ Original Code (or portions thereof).
+
+ (c) the licenses granted in this Section 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ Original Code under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: 1) for code that You delete from the Original Code; 2)
+ separate from the Original Code; or 3) for infringements caused
+ by: i) the modification of the Original Code or ii) the
+ combination of the Original Code with other software or devices.
+
+ 2.2. Contributor Grant.
+ Subject to third party intellectual property claims, each Contributor
+ hereby grants You a world-wide, royalty-free, non-exclusive license
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor, to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof) either on an
+ unmodified basis, with other Modifications, as Covered Code
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either alone
+ and/or in combination with its Contributor Version (or portions
+ of such combination), to make, use, sell, offer for sale, have
+ made, and/or otherwise dispose of: 1) Modifications made by that
+ Contributor (or portions thereof); and 2) the combination of
+ Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+
+ (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first makes Commercial Use of
+ the Covered Code.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: 1) for any code that Contributor has deleted from the
+ Contributor Version; 2) separate from the Contributor Version;
+ 3) for infringements caused by: i) third party modifications of
+ Contributor Version or ii) the combination of Modifications made
+ by that Contributor with other software (except as part of the
+ Contributor Version) or other devices; or 4) under Patent Claims
+ infringed by Covered Code in the absence of Modifications made by
+ that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Application of License.
+ The Modifications which You create or to which You contribute are
+ governed by the terms of this License, including without limitation
+ Section 2.2. The Source Code version of Covered Code may be
+ distributed only under the terms of this License or a future version
+ of this License released under Section 6.1, and You must include a
+ copy of this License with every copy of the Source Code You
+ distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this
+ License or the recipients' rights hereunder. However, You may include
+ an additional document offering the additional rights described in
+ Section 3.5.
+
+ 3.2. Availability of Source Code.
+ Any Modification which You create or to which You contribute must be
+ made available in Source Code form under the terms of this License
+ either on the same media as an Executable version or via an accepted
+ Electronic Distribution Mechanism to anyone to whom you made an
+ Executable version available; and if made available via Electronic
+ Distribution Mechanism, must remain available for at least twelve (12)
+ months after the date it initially became available, or at least six
+ (6) months after a subsequent version of that particular Modification
+ has been made available to such recipients. You are responsible for
+ ensuring that the Source Code version remains available even if the
+ Electronic Distribution Mechanism is maintained by a third party.
+
+ 3.3. Description of Modifications.
+ You must cause all Covered Code to which You contribute to contain a
+ file documenting the changes You made to create that Covered Code and
+ the date of any change. You must include a prominent statement that
+ the Modification is derived, directly or indirectly, from Original
+ Code provided by the Initial Developer and including the name of the
+ Initial Developer in (a) the Source Code, and (b) in any notice in an
+ Executable version or related documentation in which You describe the
+ origin or ownership of the Covered Code.
+
+ 3.4. Intellectual Property Matters
+ (a) Third Party Claims.
+ If Contributor has knowledge that a license under a third party's
+ intellectual property rights is required to exercise the rights
+ granted by such Contributor under Sections 2.1 or 2.2,
+ Contributor must include a text file with the Source Code
+ distribution titled "LEGAL" which describes the claim and the
+ party making the claim in sufficient detail that a recipient will
+ know whom to contact. If Contributor obtains such knowledge after
+ the Modification is made available as described in Section 3.2,
+ Contributor shall promptly modify the LEGAL file in all copies
+ Contributor makes available thereafter and shall take other steps
+ (such as notifying appropriate mailing lists or newsgroups)
+ reasonably calculated to inform those who received the Covered
+ Code that new knowledge has been obtained.
+
+ (b) Contributor APIs.
+ If Contributor's Modifications include an application programming
+ interface and Contributor has knowledge of patent licenses which
+ are reasonably necessary to implement that API, Contributor must
+ also include this information in the LEGAL file.
+
+ (c) Representations.
+ Contributor represents that, except as disclosed pursuant to
+ Section 3.4(a) above, Contributor believes that Contributor's
+ Modifications are Contributor's original creation(s) and/or
+ Contributor has sufficient rights to grant the rights conveyed by
+ this License.
+
+ 3.5. Required Notices.
+ You must duplicate the notice in Exhibit A in each file of the Source
+ Code. If it is not possible to put such notice in a particular Source
+ Code file due to its structure, then You must include such notice in a
+ location (such as a relevant directory) where a user would be likely
+ to look for such a notice. If You created one or more Modification(s)
+ You may add your name as a Contributor to the notice described in
+ Exhibit A. You must also duplicate this License in any documentation
+ for the Source Code where You describe recipients' rights or ownership
+ rights relating to Covered Code. You may choose to offer, and to
+ charge a fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Code. However, You
+ may do so only on Your own behalf, and not on behalf of the Initial
+ Developer or any Contributor. You must make it absolutely clear than
+ any such warranty, support, indemnity or liability obligation is
+ offered by You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty,
+ support, indemnity or liability terms You offer.
+
+ 3.6. Distribution of Executable Versions.
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered Code,
+ and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License,
+ including a description of how and where You have fulfilled the
+ obligations of Section 3.2. The notice must be conspicuously included
+ in any notice in an Executable version, related documentation or
+ collateral in which You describe recipients' rights relating to the
+ Covered Code. You may distribute the Executable version of Covered
+ Code or ownership rights under a license of Your choice, which may
+ contain terms different from this License, provided that You are in
+ compliance with the terms of this License and that the license for the
+ Executable version does not attempt to limit or alter the recipient's
+ rights in the Source Code version from the rights set forth in this
+ License. If You distribute the Executable version under a different
+ license You must make it absolutely clear that any terms which differ
+ from this License are offered by You alone, not by the Initial
+ Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by
+ the Initial Developer or such Contributor as a result of any such
+ terms You offer.
+
+ 3.7. Larger Works.
+ You may create a Larger Work by combining Covered Code with other code
+ not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to
+ statute, judicial order, or regulation then You must: (a) comply with
+ the terms of this License to the maximum extent possible; and (b)
+ describe the limitations and the code they affect. Such description
+ must be included in the LEGAL file described in Section 3.4 and must
+ be included with all distributions of the Source Code. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Application of this License.
+
+ This License applies to code to which the Initial Developer has
+ attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+ 6.1. New Versions.
+ Netscape Communications Corporation ("Netscape") may publish revised
+ and/or new versions of the License from time to time. Each version
+ will be given a distinguishing version number.
+
+ 6.2. Effect of New Versions.
+ Once Covered Code has been published under a particular version of the
+ License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms
+ of any subsequent version of the License published by Netscape. No one
+ other than Netscape has the right to modify the terms applicable to
+ Covered Code created under this License.
+
+ 6.3. Derivative Works.
+ If You create or use a modified version of this License (which you may
+ only do in order to apply it to code which is not already Covered Code
+ governed by this License), You must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+ "MPL", "NPL" or any confusingly similar phrase do not appear in your
+ license (except to note that your license differs from this License)
+ and (b) otherwise make it clear that Your version of the license
+ contains terms which differ from the Mozilla Public License and
+ Netscape Public License. (Filling in the name of the Initial
+ Developer, Original Code or Contributor in the notice described in
+ Exhibit A shall not of themselves be deemed to be modifications of
+ this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+ DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+ IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+ YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+ COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+ OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+ 8.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall
+ survive any termination of this License. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License
+ shall survive.
+
+ 8.2. If You initiate litigation by asserting a patent infringement
+ claim (excluding declatory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom
+ You file such action is referred to as "Participant") alleging that:
+
+ (a) such Participant's Contributor Version directly or indirectly
+ infringes any patent, then any and all rights granted by such
+ Participant to You under Sections 2.1 and/or 2.2 of this License
+ shall, upon 60 days notice from Participant terminate prospectively,
+ unless if within 60 days after receipt of notice You either: (i)
+ agree in writing to pay Participant a mutually agreeable reasonable
+ royalty for Your past and future use of Modifications made by such
+ Participant, or (ii) withdraw Your litigation claim with respect to
+ the Contributor Version against such Participant. If within 60 days
+ of notice, a reasonable royalty and payment arrangement are not
+ mutually agreed upon in writing by the parties or the litigation claim
+ is not withdrawn, the rights granted by Participant to You under
+ Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+ the 60 day notice period specified above.
+
+ (b) any software, hardware, or device, other than such Participant's
+ Contributor Version, directly or indirectly infringes any patent, then
+ any rights granted to You by such Participant under Sections 2.1(b)
+ and 2.2(b) are revoked effective as of the date You first made, used,
+ sold, distributed, or had made, Modifications made by that
+ Participant.
+
+ 8.3. If You assert a patent infringement claim against Participant
+ alleging that such Participant's Contributor Version directly or
+ indirectly infringes any patent where such claim is resolved (such as
+ by license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 8.4. In the event of termination under Sections 8.1 or 8.2 above,
+ all end user license agreements (excluding distributors and resellers)
+ which have been validly granted by You or any distributor hereunder
+ prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+ DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+ OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+ CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+ WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+ The Covered Code is a "commercial item," as that term is defined in
+ 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" and "commercial computer software documentation," as such
+ terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+ C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+ all U.S. Government End Users acquire Covered Code with only those
+ rights set forth herein.
+
+11. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ With respect to disputes in which at least one party is a citizen of,
+ or an entity chartered or registered to do business in the United
+ States of America, any litigation relating to this License shall be
+ subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys' fees and
+ expenses. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly excluded.
+ Any law or regulation which provides that the language of a contract
+ shall be construed against the drafter shall not apply to this
+ License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+ Initial Developer may designate portions of the Covered Code as
+ "Multiple-Licensed". "Multiple-Licensed" means that the Initial
+ Developer permits you to utilize portions of the Covered Code under
+ Your choice of the NPL or the alternative licenses, if any, specified
+ by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+ ``The contents of this file are subject to the Mozilla Public License
+ Version 1.1 (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.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ License for the specific language governing rights and limitations
+ under the License.
+
+ The Original Code is ______________________________________.
+
+ The Initial Developer of the Original Code is ________________________.
+ Portions created by ______________________ are Copyright (C) ______
+ _______________________. All Rights Reserved.
+
+ Contributor(s): ______________________________________.
+
+ Alternatively, the contents of this file may be used under the terms
+ of the _____ license (the "[___] License"), in which case the
+ provisions of [______] License are applicable instead of those
+ above. If you wish to allow use of your version of this file only
+ under the terms of the [____] License and not to allow others to use
+ your version of this file under the MPL, indicate your decision by
+ deleting the provisions above and replace them with the notice and
+ other provisions required by the [___] License. If you do not delete
+ the provisions above, a recipient may use your version of this file
+ under either the MPL or the [___] License."
+
+ [NOTE: The text of this Exhibit A may differ slightly from the text of
+ the notices in the Source Code files of the Original Code. You should
+ use the text of this Exhibit A rather than the text found in the
+ Original Code Source Code for Your Modifications.]
+
+### Microsoft Public License
+
+Microsoft Permissive License (Ms-PL)
+
+ This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
+
+1. Definitions
+
+ The terms \93reproduce,\94 \93reproduction,\94 \93derivative works,\94 and \93distribution\94 have the same meaning here as under U.S. copyright law.
+ A \93contribution\94 is the original software, or any additions or changes to the software.
+ A \93contributor\94 is any person that distributes its contribution under this license.
+ \93Licensed patents\94 are a contributor\92s patent claims that read directly on its contribution.
+
+2. Grant of Rights
+
+ (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
+ (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
+
+3. Conditions and Limitations
+
+ (A) No Trademark License- This license does not grant you rights to use any contributors\92 name, logo, or trademarks.
+ (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
+ (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
+ (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
+ (E) The software is licensed \93as-is.\94 You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
+ (F) If you distribute the software or derivative works with programs you develop, you agree to indemnify, defend, and hold harmless all contributors from any claims, including attorneys\92 fees, related to the distribution or use of your programs. For clarity, you have no such obligations to a contributor for any claims based solely on the unmodified contributions of that contributor.
+ (G) If you make any additions or changes to the original software, you may only distribute them under a new namespace. In addition, you will clearly identify your changes or additions as your own.
+
+### Infozip BSD
+
+This is version 2009-Jan-02 of the Info-ZIP license. The definitive
+version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and a
+copy at http://www.info-zip.org/pub/infozip/license.html.
+
+Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
+
+For the purposes of this copyright and license, "Info-ZIP" is defined
+as the following set of individuals: Mark Adler, John Bush, Karl
+Davis, Harald Denker, Jean-Michel Dubois, Jean-loup Gailly, Hunter
+Goatley, Ed Gordon, Ian Gorman, Chris Herborth, Dirk Haase, Greg
+Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David
+Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve
+P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
+Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+Rich Wales, Mike White.
+
+This software is provided "as is," without warranty of any kind,
+express or implied. In no event shall Info-ZIP or its contributors be
+held liable for any direct, indirect, incidental, special or
+consequential damages arising out of the use of or inability to use
+this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the above disclaimer and the following
+restrictions:
+
+Redistributions of source code (in whole or in part) must retain the
+above copyright notice, definition, disclaimer, and this list of
+conditions.
+
+Redistributions in binary form (compiled executables and libraries)
+must reproduce the above copyright notice, definition, disclaimer, and
+this list of conditions in documentation and/or other materials
+provided with the distribution. Additional documentation is not needed
+for executables where a command line license option provides these and
+a note regarding this option is in the executable's startup
+banner. The sole exception to this condition is redistribution of a
+standard UnZipSFX binary (including SFXWiz) as part of a
+self-extracting archive; that is permitted without inclusion of this
+license, as long as the normal SFX banner has not been removed from
+the binary or disabled.
+
+Altered versions--including, but not limited to, ports to new
+operating systems, existing ports with new graphical interfaces,
+versions with modified or added functionality, and dynamic, shared, or
+static library versions not from Info-ZIP--must be plainly marked as
+such and must not be misrepresented as being the original source or,
+if binaries, compiled from the original source. Such altered versions
+also must not be misrepresented as being Info-ZIP releases--including,
+but not limited to, labeling of the altered versions with the names
+"Info-ZIP" (or any variation thereof, including, but not limited to,
+different capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without
+the explicit permission of Info-ZIP. Such altered versions are further
+prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP
+e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP
+will provide support for the altered versions.
+
+Info-ZIP retains the right to use the names "Info-ZIP," "Zip,"
+"UnZip," "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip"
+for its own source and binary releases.
+
+### License Creative Commons 2.5
+
+// Copyright 2006 James Newton-King
+// http://www.newtonsoft.com
+//
+// This work is licensed under the Creative Commons Attribution 2.5 License
+// http://creativecommons.org/licenses/by/2.5/
+//
+// You are free:
+// * to copy, distribute, display, and perform the work
+// * to make derivative works
+// * to make commercial use of the work
+//
+// Under the following conditions:
+// * For any reuse or distribution, you must make clear to others the license terms of this work.
+// * Any of these conditions can be waived if you get permission from the copyright holder.
+
+From: james.newtonking@gmail.com [mailto:james.newtonking@gmail.com] On Behalf Of James Newton-King
+Sent: Tuesday, June 05, 2007 6:36 AM
+To: Konstantin Triger
+Subject: Re: Support request by Konstantin Triger for Json.NET
+
+Hey Kosta
+
+I think it would be awesome to use Json.NET in Mono for System.Web.Extensions.
+
+The CC license has the following clause: Any of the above conditions can be waived if you get permission from the copyright holder.
+
+I can waive that statement for you and Mono. Would that be acceptable?
+
+
+Regards,
+James
+
+### Creative Commons Attribution 4.0 International Public License
+
+Attribution 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More_considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution 4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution 4.0 International Public License ("Public License"). To the
+extent this Public License may be interpreted as a contract, You are
+granted the Licensed Rights in consideration of Your acceptance of
+these terms and conditions, and the Licensor grants You such rights in
+consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ d. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ f. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ g. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ h. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ i. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ j. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ k. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part; and
+
+ b. produce, reproduce, and Share Adapted Material.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ 4. If You Share Adapted Material You produce, the Adapter's
+ License You apply must not prevent recipients of the Adapted
+ Material from complying with this Public License.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material; and
+
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.” The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
+
+### GPL version 2
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
- GNU GPL: details avaliable in the file mcs/LICENSE.GPL
- GNU LGPL: details available in the file mcs/LICENSE.LGPL
- MIT X11: text available in the file mcs/MIT.X11
- MPL: text available in the file mcs/LICENSE.MPL
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+Microsoft Patent Promise for Mono
+
+Microsoft Corporation and its affiliates (“Microsoft”) promise not to
+assert any Applicable Patents against you for making, using, selling,
+offering for sale, importing, or distributing Mono.
+
+If you file, maintain, or voluntarily participate in any claim in a
+lawsuit alleging direct or contributory patent infringement by Mono,
+or inducement of patent infringement by Mono, then your rights under
+this promise will automatically terminate.
+
+This promise is not an assurance that (i) any Applicable Patents are
+valid or enforceable or (ii) Mono does not infringe patents or other
+intellectual property rights of any third party. No rights except
+those expressly stated in this promise are granted, waived or received
+by Microsoft, whether by implication, exhaustion, estoppel or
+otherwise. This is a personal promise directly from Microsoft to you,
+and you agree as a condition of benefitting from it that no Microsoft
+rights are received from suppliers, distributors, or otherwise in
+connection with this promise.
+
+Definitions:
+
+“Mono” means those portions of the software development technology, as
+originally distributed by Xamarin, Inc. or the .NET Foundation under
+the name “Mono,” that implement .NET Framework Functionality, provided
+that such portions at a minimum implement all of the required parts of
+the mandatory provisions of Standard ECMA-335 – Common Language
+Infrastructure (CLI).
+
+“.NET Framework Functionality” means any functionality in Microsoft’s
+.NET Framework as described in Microsoft’s API documentation on
+Microsoft’s MSDN website, including the functionality in
+Windowsbase.dll, but excluding all other functionality in the Windows
+Presentation Foundation component of .NET Framework.
+
+“Applicable Patents” are those patent claims, currently owned by
+Microsoft and acquired in the future, that are necessarily infringed
+by Mono. For clarity, Applicable Patents do not include any patent
+claims that are infringed (x) by any underlying or enabling technology
+that may be used, combined, or distributed in connection with Mono
+(such as hardware, operating systems, or applications that run on
+Mono), (y) only as a consequence of modification of Mono, or (z) only
+by the combination of Mono with third party code.
implementation of Microsoft's .NET Framework based on the ECMA
standards for C# and the Common Language Runtime.
+The Mono project is part of the [.NET Foundation](http://www.dotnetfoundation.org/)
+
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mono/mono?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
1. [Compilation and Installation](#compilation-and-installation)
Directory Roadmap
=================
+* `acceptance-tests/` - Optional third party test suites used to validate Mono against a wider range of test cases.
+
* `data/` - Configuration files installed as part of the Mono runtime.
* `docs/` - Technical documents about the Mono runtime.
The desired output diff is a change in `.gitmodules` to reflect the
change in the remote URL, and a change in /<submodule> where you see
the desired change in the commit hash.
+
+License
+=======
+
+See the LICENSE file for licensing information, and the PATENTS.TXT
+file for information about Microsoft's patent grant.
+
+Mono Trademark Use Policy
+=======
+
+The use of trademarks and logos for Mono can be found [here] (http://www.dotnetfoundation.org/legal/mono-tm).
+
{
"name": "ms-test-suite",
"url": "git@github.com:xamarin/ms-test-suite.git",
- "rev": "1ab0d4972937bf0451fc164f39a67475776a9edf",
+ "rev": "4a95604fdf2c0523e68eaad64a17d22eebb051b3",
"remote-branch": "origin/master",
"branch": "master",
"directory": "ms-test-suite"
check-ms-test-suite:
@if $(MAKE) validate-ms-test-suite RESET_VERSIONS=1; then \
- $(MAKE) -C $(MSTESTSUITE_PATH)/conformance build MCS="$(MCS) -t:library -warn:1 -r:nunit.framework"; \
- $(MAKE) -C $(MSTESTSUITE_PATH)/conformance run NUNIT-CONSOLE="$(RUNTIME) $(CLASS)/nunit-console.exe -nologo -exclude=MonoBug,BadTest" NUNIT_XML_RESULT=$(abs_top_builddir)/acceptance-tests/TestResult-ms-test-suite-conformance.xml; \
- $(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup build MCS="$(MCS) -debug -warn:1"; \
- $(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup run MONO="$(RUNTIME)"; \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/conformance build MCS="$(MCS) -t:library -warn:1 -r:nunit.framework" && \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/conformance run NUNIT-CONSOLE="$(RUNTIME) $(CLASS)/nunit-console.exe -nologo -exclude=MonoBug,BadTest" NUNIT_XML_RESULT=$(abs_top_builddir)/acceptance-tests/TestResult-ms-test-suite-conformance.xml || EXIT_CODE=1; \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup build MCS="$(MCS) -debug -warn:1" && \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup run MONO="$(RUNTIME)" || EXIT_CODE=1; \
+ exit $$EXIT_CODE; \
else \
echo "*** [ms-test-suite] Getting the repository failed, you probably don't have access to this Xamarin-internal resource. Skipping."; \
fi
\ No newline at end of file
cd $(ROSLYN_PATH); \
sed -i -e 'N; s/bootstrapArg=".*\n.*"/bootstrapArg=""/g' cibuild.sh; \
sed -i -e 's#-xml Binaries/\$$BUILD_CONFIGURATION/xUnitResults/#-nunit $(abs_top_builddir)/acceptance-tests/TestResult-#g' cibuild.sh; \
- ./cibuild.sh --mono-path $$PREFIX/bin; \
- sed -i -e 's/\\4.5"/\\4.5-api"/g' $$PREFIX/lib/mono/xbuild-frameworks/.NETFramework/v4.5/RedistList/FrameworkList.xml;
+ ./cibuild.sh --mono-path $$PREFIX/bin || EXIT_CODE=1; \
+ sed -i -e 's/\\4.5"/\\4.5-api"/g' $$PREFIX/lib/mono/xbuild-frameworks/.NETFramework/v4.5/RedistList/FrameworkList.xml; \
+ exit $$EXIT_CODE
AC_MSG_NOTICE([Enabling mono extension module.])
fi
-AC_ARG_ENABLE(gsharedvt, [ --enable-gsharedvt Enable generic valuetype sharing], enable_gsharedvt=$enableval, enable_gsharedvt=no)
-if test x$enable_gsharedvt = xyes; then
- AC_DEFINE(ENABLE_GSHAREDVT,1,[Gsharedvt])
-fi
-
-AC_ARG_ENABLE(native-types, [ --enable-native-types Enable native types], enable_native_types=$enableval, enable_native_types=no)
-if test x$enable_native_types = xyes; then
- AC_DEFINE(MONO_NATIVE_TYPES,1,[native types])
-fi
+# Deprecated
+AC_ARG_ENABLE(gsharedvt, [ --enable-gsharedvt Enable generic valuetype sharing (Deprecated)], enable_gsharedvt=$enableval, enable_gsharedvt=no)
AC_MSG_CHECKING(for visibility __attribute__)
AC_COMPILE_IFELSE([
# default install location
libgdiplus_install_loc=libgdiplus${libsuffix}
+case "$host" in
+ *-*-*linux*)
+ libgdiplus_install_loc=libgdiplus${libsuffix}.0
+ ;;
+esac
+
case $with_libgdiplus in
no|installed)
libgdiplus_loc=
fi
], [with_cooperative_gc=no])
-AC_ARG_WITH(checked_build, [ --with-checked-build=yes|no Enable checked build (expensive asserts)) (defaults to no)],[
- if test x$with_checked_build != xno ; then
- AC_DEFINE(CHECKED_BUILD,1,[Enable checked build.])
- fi
-], [with_checked_build=no])
+AC_ARG_ENABLE(checked_build, [ --enable-checked-build=LIST To enable checked build (expensive asserts), configure with a comma-separated LIST of checked build modules and then include that same list in the environment variable MONO_CHECK_MODE at runtime. Recognized checked build modules: all, gc, metadata, thread],[
-if test x$with_checked_build != xno ; then
- DISABLED_CHECKED_BUILD_TEST=none
+ if test x$enable_checked_build != x ; then
+ AC_DEFINE(ENABLE_CHECKED_BUILD,1,[Enable checked build])
+ fi
+ for feature in `echo "$enable_checked_build" | sed -e "s/,/ /g"`; do
+ eval "mono_checked_build_test_enable_$feature='yes'"
+ done
- AC_ARG_ENABLE(checked_build_test, [ --enable-checked-build-test=LIST drop support for LIST checked build tests. LIST is a comma-separated list from: gc, metadata, thread.],
- [
- for feature in `echo "$enable_checked_build_test" | sed -e "s/,/ /g"`; do
- eval "mono_checked_build_test_disable_$feature='yes'"
- done
- DISABLED_CHECKED_BUILD_TEST=$enable_checked_build_test
- ],[])
+ if test "x$mono_checked_build_test_enable_all" = "xyes"; then
+ eval "mono_checked_build_test_enable_gc='yes'"
+ eval "mono_checked_build_test_enable_metadata='yes'"
+ eval "mono_checked_build_test_enable_thread='yes'"
+ fi
- if test "x$mono_checked_build_test_disable_gc" = "xyes"; then
- AC_DEFINE(DISABLE_CHECKED_BUILD_GC, 1, [Disable GC checked build])
+ if test "x$mono_checked_build_test_enable_gc" = "xyes"; then
+ AC_DEFINE(ENABLE_CHECKED_BUILD_GC, 1, [Enable GC checked build])
fi
- if test "x$mono_checked_build_test_disable_metadata" = "xyes"; then
- AC_DEFINE(DISABLE_CHECKED_BUILD_METADATA, 1, [Disable metadata checked build])
+ if test "x$mono_checked_build_test_enable_metadata" = "xyes"; then
+ AC_DEFINE(ENABLE_CHECKED_BUILD_METADATA, 1, [Enable metadata checked build])
fi
- if test "x$mono_checked_build_test_disable_thread" = "xyes"; then
- AC_DEFINE(DISABLE_CHECKED_BUILD_THREAD, 1, [Disable thread checked build])
+ if test "x$mono_checked_build_test_enable_thread" = "xyes"; then
+ AC_DEFINE(ENABLE_CHECKED_BUILD_THREAD, 1, [Enable thread checked build])
fi
-fi
+
+], [])
AC_CHECK_HEADER([malloc.h],
[AC_DEFINE([HAVE_USR_INCLUDE_MALLOC_H], [1],
if test x$has_extension_module != xno; then
echo "EXTENSION_MODULE = 1" >> $srcdir/$mcsdir/build/config.make
fi
-
- if test x$enable_gsharedvt = xno; then
- echo "MONO_DISABLE_GSHAREDVT = 1" >> $srcdir/$mcsdir/build/config.make
- fi
echo "DEFAULT_PROFILE = $default_profile" >> $srcdir/$mcsdir/build/config.make
-Subproject commit 35b7594b5498e9712522e0556ec290415691dddd
+Subproject commit 6c6e36218c4a0b6dfb85bd27fa6746467761e8a0
this mode can be enabled at compile time by using the --with-cooperative-gc
flag when calling configure.
.TP
-\fBMONO_ENABLE_SHM\fR
-Unix only: Enable support for cross-process handles. Cross-process
-handles are used to expose process handles, thread handles, named
-mutexes, named events and named semaphores across Unix processes.
-.TP
\fBMONO_ENV_OPTIONS\fR
This environment variable allows you to pass command line arguments to
a Mono process through the environment. This is useful for example
+++ /dev/null
- GNU LIBRARY GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1991 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the library GPL. It is
- numbered 2 because it goes with version 2 of the ordinary GPL.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Library General Public License, applies to some
-specially designated Free Software Foundation software, and to any
-other libraries whose authors decide to use it. You can use it for
-your libraries, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if
-you distribute copies of the library, or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link a program with the library, you must provide
-complete object files to the recipients so that they can relink them
-with the library, after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- Our method of protecting your rights has two steps: (1) copyright
-the library, and (2) offer you this license which gives you legal
-permission to copy, distribute and/or modify the library.
-
- Also, for each distributor's protection, we want to make certain
-that everyone understands that there is no warranty for this free
-library. If the library is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original
-version, so that any problems introduced by others will not reflect on
-the original authors' reputations.
-\f
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that companies distributing free
-software will individually obtain patent licenses, thus in effect
-transforming the program into proprietary software. To prevent this,
-we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
- Most GNU software, including some libraries, is covered by the ordinary
-GNU General Public License, which was designed for utility programs. This
-license, the GNU Library General Public License, applies to certain
-designated libraries. This license is quite different from the ordinary
-one; be sure to read it in full, and don't assume that anything in it is
-the same as in the ordinary license.
-
- The reason we have a separate public license for some libraries is that
-they blur the distinction we usually make between modifying or adding to a
-program and simply using it. Linking a program with a library, without
-changing the library, is in some sense simply using the library, and is
-analogous to running a utility program or application program. However, in
-a textual and legal sense, the linked executable is a combined work, a
-derivative of the original library, and the ordinary General Public License
-treats it as such.
-
- Because of this blurred distinction, using the ordinary General
-Public License for libraries did not effectively promote software
-sharing, because most developers did not use the libraries. We
-concluded that weaker conditions might promote sharing better.
-
- However, unrestricted linking of non-free programs would deprive the
-users of those programs of all benefit from the free status of the
-libraries themselves. This Library General Public License is intended to
-permit developers of non-free programs to use free libraries, while
-preserving your freedom as a user of such programs to change the free
-libraries that are incorporated in them. (We have not seen how to achieve
-this as regards changes in header files, but we have achieved it as regards
-changes in the actual functions of the Library.) The hope is that this
-will lead to faster development of free libraries.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, while the latter only
-works together with the library.
-
- Note that it is possible for a library to be covered by the ordinary
-General Public License rather than by this special one.
-\f
- GNU LIBRARY GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library which
-contains a notice placed by the copyright holder or other authorized
-party saying it may be distributed under the terms of this Library
-General Public License (also called "this License"). Each licensee is
-addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-\f
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-\f
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-\f
- 6. As an exception to the Sections above, you may also compile or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- c) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- d) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the source code distributed need not include anything that is normally
-distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-\f
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-\f
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Library General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-\f
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-\f
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
+++ /dev/null
-
-The Mono code under the mcs/ directory is licensed under various
-different licenses:
-
- GNU GPL: details avaliable in the file LICENSE.GPL
- GNU LGPL: details available in the file LICENSE.LGPL
- MIT X11: text available in the file MIT.X11
- MPL: text available in the file LICENSE.MPL
-
- For your convenience copies of the GNU GPL and GNU LGPL are
- located in the file COPYING and COPYING.LIB.
-
- * Class Libraries:
-
- All of the core classes licensed under the terms of
- the MIT X11 license.
-
- Third party libraries that we distribute for
- convenience reasons are distributed under their own
- terms (all of them allow development of proprietary
- applications with them).
-
- Third party libraries include: ByteFX.Data,
- ICSharpCode.SharpZipLib, Npgsql, MicrosoftAjaxLibrary.
-
- The Microsoft.JScript assembly is covered by the
- MIT X11 and the Mozilla MPL license as it contains
- ported pieces of code from Rhino, the Mozilla JavaScript
- implementations
-
- * Mono C# compiler: Dual licensed MIT X11 and GNU GPL.
-
- * Mono Basic compiler: GNU GPL.
-
- * Various tools in the `tools' directory: GNU GPL.
-
+++ /dev/null
-// Copyright 2006 James Newton-King
-// http://www.newtonsoft.com
-//
-// This work is licensed under the Creative Commons Attribution 2.5 License
-// http://creativecommons.org/licenses/by/2.5/
-//
-// You are free:
-// * to copy, distribute, display, and perform the work
-// * to make derivative works
-// * to make commercial use of the work
-//
-// Under the following conditions:
-// * For any reuse or distribution, you must make clear to others the license terms of this work.
-// * Any of these conditions can be waived if you get permission from the copyright holder.
-
-From: james.newtonking@gmail.com [mailto:james.newtonking@gmail.com] On Behalf Of James Newton-King
-Sent: Tuesday, June 05, 2007 6:36 AM
-To: Konstantin Triger
-Subject: Re: Support request by Konstantin Triger for Json.NET
-
-Hey Kosta
-
-I think it would be awesome to use Json.NET in Mono for System.Web.Extensions.
-
-The CC license has the following clause: Any of the above conditions can be waived if you get permission from the copyright holder.
-
-I can waive that statement for you and Mono. Would that be acceptable?
-
-
-Regards,
-James
+++ /dev/null
- Mono compilers and tools.
- Copyright (C) 2001, 2002, 2003, Ximian and contributors.
-
- 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;
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+++ /dev/null
- Mono class libraries
- Copyright (C) Mono project (authors listed in individual ChangeLog entries)
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+++ /dev/null
- MOZILLA PUBLIC LICENSE
- Version 1.1
-
- ---------------
-
-1. Definitions.
-
- 1.0.1. "Commercial Use" means distribution or otherwise making the
- Covered Code available to a third party.
-
- 1.1. "Contributor" means each entity that creates or contributes to
- the creation of Modifications.
-
- 1.2. "Contributor Version" means the combination of the Original
- Code, prior Modifications used by a Contributor, and the Modifications
- made by that particular Contributor.
-
- 1.3. "Covered Code" means the Original Code or Modifications or the
- combination of the Original Code and Modifications, in each case
- including portions thereof.
-
- 1.4. "Electronic Distribution Mechanism" means a mechanism generally
- accepted in the software development community for the electronic
- transfer of data.
-
- 1.5. "Executable" means Covered Code in any form other than Source
- Code.
-
- 1.6. "Initial Developer" means the individual or entity identified
- as the Initial Developer in the Source Code notice required by Exhibit
- A.
-
- 1.7. "Larger Work" means a work which combines Covered Code or
- portions thereof with code not governed by the terms of this License.
-
- 1.8. "License" means this document.
-
- 1.8.1. "Licensable" means having the right to grant, to the maximum
- extent possible, whether at the time of the initial grant or
- subsequently acquired, any and all of the rights conveyed herein.
-
- 1.9. "Modifications" means any addition to or deletion from the
- substance or structure of either the Original Code or any previous
- Modifications. When Covered Code is released as a series of files, a
- Modification is:
- A. Any addition to or deletion from the contents of a file
- containing Original Code or previous Modifications.
-
- B. Any new file that contains any part of the Original Code or
- previous Modifications.
-
- 1.10. "Original Code" means Source Code of computer software code
- which is described in the Source Code notice required by Exhibit A as
- Original Code, and which, at the time of its release under this
- License is not already Covered Code governed by this License.
-
- 1.10.1. "Patent Claims" means any patent claim(s), now owned or
- hereafter acquired, including without limitation, method, process,
- and apparatus claims, in any patent Licensable by grantor.
-
- 1.11. "Source Code" means the preferred form of the Covered Code for
- making modifications to it, including all modules it contains, plus
- any associated interface definition files, scripts used to control
- compilation and installation of an Executable, or source code
- differential comparisons against either the Original Code or another
- well known, available Covered Code of the Contributor's choice. The
- Source Code can be in a compressed or archival form, provided the
- appropriate decompression or de-archiving software is widely available
- for no charge.
-
- 1.12. "You" (or "Your") means an individual or a legal entity
- exercising rights under, and complying with all of the terms of, this
- License or a future version of this License issued under Section 6.1.
- For legal entities, "You" includes any entity which controls, is
- controlled by, or is under common control with You. For purposes of
- this definition, "control" means (a) the power, direct or indirect,
- to cause the direction or management of such entity, whether by
- contract or otherwise, or (b) ownership of more than fifty percent
- (50%) of the outstanding shares or beneficial ownership of such
- entity.
-
-2. Source Code License.
-
- 2.1. The Initial Developer Grant.
- The Initial Developer hereby grants You a world-wide, royalty-free,
- non-exclusive license, subject to third party intellectual property
- claims:
- (a) under intellectual property rights (other than patent or
- trademark) Licensable by Initial Developer to use, reproduce,
- modify, display, perform, sublicense and distribute the Original
- Code (or portions thereof) with or without Modifications, and/or
- as part of a Larger Work; and
-
- (b) under Patents Claims infringed by the making, using or
- selling of Original Code, to make, have made, use, practice,
- sell, and offer for sale, and/or otherwise dispose of the
- Original Code (or portions thereof).
-
- (c) the licenses granted in this Section 2.1(a) and (b) are
- effective on the date Initial Developer first distributes
- Original Code under the terms of this License.
-
- (d) Notwithstanding Section 2.1(b) above, no patent license is
- granted: 1) for code that You delete from the Original Code; 2)
- separate from the Original Code; or 3) for infringements caused
- by: i) the modification of the Original Code or ii) the
- combination of the Original Code with other software or devices.
-
- 2.2. Contributor Grant.
- Subject to third party intellectual property claims, each Contributor
- hereby grants You a world-wide, royalty-free, non-exclusive license
-
- (a) under intellectual property rights (other than patent or
- trademark) Licensable by Contributor, to use, reproduce, modify,
- display, perform, sublicense and distribute the Modifications
- created by such Contributor (or portions thereof) either on an
- unmodified basis, with other Modifications, as Covered Code
- and/or as part of a Larger Work; and
-
- (b) under Patent Claims infringed by the making, using, or
- selling of Modifications made by that Contributor either alone
- and/or in combination with its Contributor Version (or portions
- of such combination), to make, use, sell, offer for sale, have
- made, and/or otherwise dispose of: 1) Modifications made by that
- Contributor (or portions thereof); and 2) the combination of
- Modifications made by that Contributor with its Contributor
- Version (or portions of such combination).
-
- (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
- effective on the date Contributor first makes Commercial Use of
- the Covered Code.
-
- (d) Notwithstanding Section 2.2(b) above, no patent license is
- granted: 1) for any code that Contributor has deleted from the
- Contributor Version; 2) separate from the Contributor Version;
- 3) for infringements caused by: i) third party modifications of
- Contributor Version or ii) the combination of Modifications made
- by that Contributor with other software (except as part of the
- Contributor Version) or other devices; or 4) under Patent Claims
- infringed by Covered Code in the absence of Modifications made by
- that Contributor.
-
-3. Distribution Obligations.
-
- 3.1. Application of License.
- The Modifications which You create or to which You contribute are
- governed by the terms of this License, including without limitation
- Section 2.2. The Source Code version of Covered Code may be
- distributed only under the terms of this License or a future version
- of this License released under Section 6.1, and You must include a
- copy of this License with every copy of the Source Code You
- distribute. You may not offer or impose any terms on any Source Code
- version that alters or restricts the applicable version of this
- License or the recipients' rights hereunder. However, You may include
- an additional document offering the additional rights described in
- Section 3.5.
-
- 3.2. Availability of Source Code.
- Any Modification which You create or to which You contribute must be
- made available in Source Code form under the terms of this License
- either on the same media as an Executable version or via an accepted
- Electronic Distribution Mechanism to anyone to whom you made an
- Executable version available; and if made available via Electronic
- Distribution Mechanism, must remain available for at least twelve (12)
- months after the date it initially became available, or at least six
- (6) months after a subsequent version of that particular Modification
- has been made available to such recipients. You are responsible for
- ensuring that the Source Code version remains available even if the
- Electronic Distribution Mechanism is maintained by a third party.
-
- 3.3. Description of Modifications.
- You must cause all Covered Code to which You contribute to contain a
- file documenting the changes You made to create that Covered Code and
- the date of any change. You must include a prominent statement that
- the Modification is derived, directly or indirectly, from Original
- Code provided by the Initial Developer and including the name of the
- Initial Developer in (a) the Source Code, and (b) in any notice in an
- Executable version or related documentation in which You describe the
- origin or ownership of the Covered Code.
-
- 3.4. Intellectual Property Matters
- (a) Third Party Claims.
- If Contributor has knowledge that a license under a third party's
- intellectual property rights is required to exercise the rights
- granted by such Contributor under Sections 2.1 or 2.2,
- Contributor must include a text file with the Source Code
- distribution titled "LEGAL" which describes the claim and the
- party making the claim in sufficient detail that a recipient will
- know whom to contact. If Contributor obtains such knowledge after
- the Modification is made available as described in Section 3.2,
- Contributor shall promptly modify the LEGAL file in all copies
- Contributor makes available thereafter and shall take other steps
- (such as notifying appropriate mailing lists or newsgroups)
- reasonably calculated to inform those who received the Covered
- Code that new knowledge has been obtained.
-
- (b) Contributor APIs.
- If Contributor's Modifications include an application programming
- interface and Contributor has knowledge of patent licenses which
- are reasonably necessary to implement that API, Contributor must
- also include this information in the LEGAL file.
-
- (c) Representations.
- Contributor represents that, except as disclosed pursuant to
- Section 3.4(a) above, Contributor believes that Contributor's
- Modifications are Contributor's original creation(s) and/or
- Contributor has sufficient rights to grant the rights conveyed by
- this License.
-
- 3.5. Required Notices.
- You must duplicate the notice in Exhibit A in each file of the Source
- Code. If it is not possible to put such notice in a particular Source
- Code file due to its structure, then You must include such notice in a
- location (such as a relevant directory) where a user would be likely
- to look for such a notice. If You created one or more Modification(s)
- You may add your name as a Contributor to the notice described in
- Exhibit A. You must also duplicate this License in any documentation
- for the Source Code where You describe recipients' rights or ownership
- rights relating to Covered Code. You may choose to offer, and to
- charge a fee for, warranty, support, indemnity or liability
- obligations to one or more recipients of Covered Code. However, You
- may do so only on Your own behalf, and not on behalf of the Initial
- Developer or any Contributor. You must make it absolutely clear than
- any such warranty, support, indemnity or liability obligation is
- offered by You alone, and You hereby agree to indemnify the Initial
- Developer and every Contributor for any liability incurred by the
- Initial Developer or such Contributor as a result of warranty,
- support, indemnity or liability terms You offer.
-
- 3.6. Distribution of Executable Versions.
- You may distribute Covered Code in Executable form only if the
- requirements of Section 3.1-3.5 have been met for that Covered Code,
- and if You include a notice stating that the Source Code version of
- the Covered Code is available under the terms of this License,
- including a description of how and where You have fulfilled the
- obligations of Section 3.2. The notice must be conspicuously included
- in any notice in an Executable version, related documentation or
- collateral in which You describe recipients' rights relating to the
- Covered Code. You may distribute the Executable version of Covered
- Code or ownership rights under a license of Your choice, which may
- contain terms different from this License, provided that You are in
- compliance with the terms of this License and that the license for the
- Executable version does not attempt to limit or alter the recipient's
- rights in the Source Code version from the rights set forth in this
- License. If You distribute the Executable version under a different
- license You must make it absolutely clear that any terms which differ
- from this License are offered by You alone, not by the Initial
- Developer or any Contributor. You hereby agree to indemnify the
- Initial Developer and every Contributor for any liability incurred by
- the Initial Developer or such Contributor as a result of any such
- terms You offer.
-
- 3.7. Larger Works.
- You may create a Larger Work by combining Covered Code with other code
- not governed by the terms of this License and distribute the Larger
- Work as a single product. In such a case, You must make sure the
- requirements of this License are fulfilled for the Covered Code.
-
-4. Inability to Comply Due to Statute or Regulation.
-
- If it is impossible for You to comply with any of the terms of this
- License with respect to some or all of the Covered Code due to
- statute, judicial order, or regulation then You must: (a) comply with
- the terms of this License to the maximum extent possible; and (b)
- describe the limitations and the code they affect. Such description
- must be included in the LEGAL file described in Section 3.4 and must
- be included with all distributions of the Source Code. Except to the
- extent prohibited by statute or regulation, such description must be
- sufficiently detailed for a recipient of ordinary skill to be able to
- understand it.
-
-5. Application of this License.
-
- This License applies to code to which the Initial Developer has
- attached the notice in Exhibit A and to related Covered Code.
-
-6. Versions of the License.
-
- 6.1. New Versions.
- Netscape Communications Corporation ("Netscape") may publish revised
- and/or new versions of the License from time to time. Each version
- will be given a distinguishing version number.
-
- 6.2. Effect of New Versions.
- Once Covered Code has been published under a particular version of the
- License, You may always continue to use it under the terms of that
- version. You may also choose to use such Covered Code under the terms
- of any subsequent version of the License published by Netscape. No one
- other than Netscape has the right to modify the terms applicable to
- Covered Code created under this License.
-
- 6.3. Derivative Works.
- If You create or use a modified version of this License (which you may
- only do in order to apply it to code which is not already Covered Code
- governed by this License), You must (a) rename Your license so that
- the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
- "MPL", "NPL" or any confusingly similar phrase do not appear in your
- license (except to note that your license differs from this License)
- and (b) otherwise make it clear that Your version of the license
- contains terms which differ from the Mozilla Public License and
- Netscape Public License. (Filling in the name of the Initial
- Developer, Original Code or Contributor in the notice described in
- Exhibit A shall not of themselves be deemed to be modifications of
- this License.)
-
-7. DISCLAIMER OF WARRANTY.
-
- COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
- DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
- THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
- IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
- YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
- COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
- OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
- ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-8. TERMINATION.
-
- 8.1. This License and the rights granted hereunder will terminate
- automatically if You fail to comply with terms herein and fail to cure
- such breach within 30 days of becoming aware of the breach. All
- sublicenses to the Covered Code which are properly granted shall
- survive any termination of this License. Provisions which, by their
- nature, must remain in effect beyond the termination of this License
- shall survive.
-
- 8.2. If You initiate litigation by asserting a patent infringement
- claim (excluding declatory judgment actions) against Initial Developer
- or a Contributor (the Initial Developer or Contributor against whom
- You file such action is referred to as "Participant") alleging that:
-
- (a) such Participant's Contributor Version directly or indirectly
- infringes any patent, then any and all rights granted by such
- Participant to You under Sections 2.1 and/or 2.2 of this License
- shall, upon 60 days notice from Participant terminate prospectively,
- unless if within 60 days after receipt of notice You either: (i)
- agree in writing to pay Participant a mutually agreeable reasonable
- royalty for Your past and future use of Modifications made by such
- Participant, or (ii) withdraw Your litigation claim with respect to
- the Contributor Version against such Participant. If within 60 days
- of notice, a reasonable royalty and payment arrangement are not
- mutually agreed upon in writing by the parties or the litigation claim
- is not withdrawn, the rights granted by Participant to You under
- Sections 2.1 and/or 2.2 automatically terminate at the expiration of
- the 60 day notice period specified above.
-
- (b) any software, hardware, or device, other than such Participant's
- Contributor Version, directly or indirectly infringes any patent, then
- any rights granted to You by such Participant under Sections 2.1(b)
- and 2.2(b) are revoked effective as of the date You first made, used,
- sold, distributed, or had made, Modifications made by that
- Participant.
-
- 8.3. If You assert a patent infringement claim against Participant
- alleging that such Participant's Contributor Version directly or
- indirectly infringes any patent where such claim is resolved (such as
- by license or settlement) prior to the initiation of patent
- infringement litigation, then the reasonable value of the licenses
- granted by such Participant under Sections 2.1 or 2.2 shall be taken
- into account in determining the amount or value of any payment or
- license.
-
- 8.4. In the event of termination under Sections 8.1 or 8.2 above,
- all end user license agreements (excluding distributors and resellers)
- which have been validly granted by You or any distributor hereunder
- prior to termination shall survive termination.
-
-9. LIMITATION OF LIABILITY.
-
- UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
- (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
- DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
- OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
- ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
- CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
- WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
- COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
- INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
- LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
- RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
- PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
- EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
- THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
-
-10. U.S. GOVERNMENT END USERS.
-
- The Covered Code is a "commercial item," as that term is defined in
- 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
- software" and "commercial computer software documentation," as such
- terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
- C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
- all U.S. Government End Users acquire Covered Code with only those
- rights set forth herein.
-
-11. MISCELLANEOUS.
-
- This License represents the complete agreement concerning subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. This License shall be governed by
- California law provisions (except to the extent applicable law, if
- any, provides otherwise), excluding its conflict-of-law provisions.
- With respect to disputes in which at least one party is a citizen of,
- or an entity chartered or registered to do business in the United
- States of America, any litigation relating to this License shall be
- subject to the jurisdiction of the Federal Courts of the Northern
- District of California, with venue lying in Santa Clara County,
- California, with the losing party responsible for costs, including
- without limitation, court costs and reasonable attorneys' fees and
- expenses. The application of the United Nations Convention on
- Contracts for the International Sale of Goods is expressly excluded.
- Any law or regulation which provides that the language of a contract
- shall be construed against the drafter shall not apply to this
- License.
-
-12. RESPONSIBILITY FOR CLAIMS.
-
- As between Initial Developer and the Contributors, each party is
- responsible for claims and damages arising, directly or indirectly,
- out of its utilization of rights under this License and You agree to
- work with Initial Developer and Contributors to distribute such
- responsibility on an equitable basis. Nothing herein is intended or
- shall be deemed to constitute any admission of liability.
-
-13. MULTIPLE-LICENSED CODE.
-
- Initial Developer may designate portions of the Covered Code as
- "Multiple-Licensed". "Multiple-Licensed" means that the Initial
- Developer permits you to utilize portions of the Covered Code under
- Your choice of the NPL or the alternative licenses, if any, specified
- by the Initial Developer in the file described in Exhibit A.
-
-EXHIBIT A -Mozilla Public License.
-
- ``The contents of this file are subject to the Mozilla Public License
- Version 1.1 (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.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
- License for the specific language governing rights and limitations
- under the License.
-
- The Original Code is ______________________________________.
-
- The Initial Developer of the Original Code is ________________________.
- Portions created by ______________________ are Copyright (C) ______
- _______________________. All Rights Reserved.
-
- Contributor(s): ______________________________________.
-
- Alternatively, the contents of this file may be used under the terms
- of the _____ license (the "[___] License"), in which case the
- provisions of [______] License are applicable instead of those
- above. If you wish to allow use of your version of this file only
- under the terms of the [____] License and not to allow others to use
- your version of this file under the MPL, indicate your decision by
- deleting the provisions above and replace them with the notice and
- other provisions required by the [___] License. If you do not delete
- the provisions above, a recipient may use your version of this file
- under either the MPL or the [___] License."
-
- [NOTE: The text of this Exhibit A may differ slightly from the text of
- the notices in the Source Code files of the Original Code. You should
- use the text of this Exhibit A rather than the text found in the
- Original Code Source Code for Your Modifications.]
-
+++ /dev/null
-Microsoft Permissive License (Ms-PL)\r
- \r
- This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.\r
- \r
-1. Definitions\r
-\r
- The terms \93reproduce,\94 \93reproduction,\94 \93derivative works,\94 and \93distribution\94 have the same meaning here as under U.S. copyright law.\r
- A \93contribution\94 is the original software, or any additions or changes to the software.\r
- A \93contributor\94 is any person that distributes its contribution under this license.\r
- \93Licensed patents\94 are a contributor\92s patent claims that read directly on its contribution.\r
- \r
-2. Grant of Rights\r
-\r
- (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.\r
- (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.\r
- \r
-3. Conditions and Limitations\r
-\r
- (A) No Trademark License- This license does not grant you rights to use any contributors\92 name, logo, or trademarks.\r
- (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.\r
- (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.\r
- (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.\r
- (E) The software is licensed \93as-is.\94 You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.\r
- (F) If you distribute the software or derivative works with programs you develop, you agree to indemnify, defend, and hold harmless all contributors from any claims, including attorneys\92 fees, related to the distribution or use of your programs. For clarity, you have no such obligations to a contributor for any claims based solely on the unmodified contributions of that contributor.\r
- (G) If you make any additions or changes to the original software, you may only distribute them under a new namespace. In addition, you will clearly identify your changes or additions as your own.\r
-\r
-\r
+++ /dev/null
-Copyright (c) 2001, 2002, 2003 Ximian, Inc and the individuals listed
-on the ChangeLog entries.
-
-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.
COPYING \
COPYING.LIB \
INSTALL.txt \
- LICENSE \
- LICENSE.GPL \
- LICENSE.LGPL \
- LICENSE.MPL \
Makefile \
mkinstalldirs \
MIT.X11 \
Thanks a lot to Sergey Chaban for his help during the development of
the C# compiler.
-* LICENSE
-=========
-
-The mcs C# compiler and monoresgen are licensed to you under the GPL, version 2.
-The complete text of the GPL is in the 'COPYING' file.
-
- Copyright (C) 2001-2002 Ximian, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-The class libraries are licensed according to the following license:
-
- Copyright (C) 2001-2002 Ximian, Inc.
-
-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.
-
Locale.cs \
MonoTODOAttribute.cs \
basic-profile-check.cs \
- SR.cs
+ SR.cs \
+ AssemblyRef.cs
DISTFILES = \
README.makefiles \
rm -f $outfile.inc
-if test -n "$excfile"; then
+if test -n "$excfile" -a -f "$excfile"; then
process_includes $excfile $outfile.exc
fi
System.XML \
System Mono.Security \
Mono.Posix \
- System.Core
+ System.Core \
+ Mono.Cecil \
+ Mono.Cecil.Mdb
pcl_facade_dirs := Facades
public void Dispose ()
{
- WaitHandle.WaitAll (submissions.Select (s => s.WaitHandle).ToArray ());
+ if (submissions.Count > 0)
+ WaitHandle.WaitAll (submissions.Select (s => s.WaitHandle).ToArray ());
BuildNodeManager.Stop ();
}
};
var requestData = new BuildRequestData (this, targets ?? DefaultTargets.ToArray ());
var result = manager.Build (parameters, requestData);
+ manager.Dispose ();
targetOutputs = result.ResultsByTarget;
return result.OverallResult == BuildResultCode.Success;
}
public BuildNodeManager (BuildManager buildManager)
{
BuildManager = buildManager;
- new Thread (RunLoop).Start ();
+ new Thread (RunLoop) {
+ IsBackground = true,
+ Name = "xbuild request handler"
+ }.Start ();
}
~BuildNodeManager ()
#
# Update this comment to trigger a build in System
-# +2
+# +3
#
*/
public virtual bool InvokeSystemCertificateValidator (
ICertificateValidator validator, string targetHost, bool serverMode,
- X509CertificateCollection certificates, X509Chain chain, out bool success,
+ X509CertificateCollection certificates, ref X509Chain chain, out bool success,
ref MonoSslPolicyErrors errors, ref int status11)
{
success = false;
#include mobile_Mono.Security.dll.sources
+../corlib/CommonCrypto/CommonCrypto.cs
+../corlib/CommonCrypto/RC4CommonCrypto.cs
+../corlib/CommonCrypto/MD2Managed.g.cs
+../corlib/CommonCrypto/MD4Managed.g.cs
+../corlib/CommonCrypto/SHA224Managed.g.cs
+++ /dev/null
-./Mono.Security.Cryptography/ARC4Managed.cs
-./Mono.Security.Cryptography/MD2Managed.cs
-./Mono.Security.Cryptography/MD4Managed.cs
-./Mono.Security.Cryptography/SHA224Managed.cs
#include monotouch_Mono.Security.dll.sources
+../corlib/CommonCrypto/CommonCrypto.cs
+../corlib/CommonCrypto/RC4CommonCrypto.cs
+../corlib/CommonCrypto/MD2Managed.g.cs
+../corlib/CommonCrypto/MD4Managed.g.cs
+../corlib/CommonCrypto/SHA224Managed.g.cs
+++ /dev/null
-./Mono.Security.Cryptography/ARC4Managed.cs
-./Mono.Security.Cryptography/MD2Managed.cs
-./Mono.Security.Cryptography/MD4Managed.cs
-./Mono.Security.Cryptography/SHA224Managed.cs
#
# Copyright (c) 2007 Novell, Inc.
#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of version 2 of the GNU General Public
-# License as published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public
-# License along with this program; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-##############################################################
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include common_System.Core.dll.sources
#include interpreter_System.Core.dll.sources
+../corlib/CommonCrypto/AesManaged.g.cs
+../corlib/CommonCrypto/AesCryptoServiceProvider.g.cs
#include common_System.Core.dll.sources
#include dynamic_System.Core.dll.sources
-
+../corlib/CommonCrypto/AesManaged.g.cs
+../corlib/CommonCrypto/AesCryptoServiceProvider.g.cs
LIBRARY = System.IO.Compression.FileSystem.dll
LIB_REFS = System System.IO.Compression
LIB_MCS_FLAGS =
-TEST_MCS_FLAGS = /r:System /r:System.Core /r:System.IO.Compression.dll
+TEST_MCS_FLAGS = /r:System.dll /r:System.Core.dll /r:System.IO.Compression.dll
include ../../build/library.make
LIBRARY = System.IO.Compression.dll
LIB_REFS = System System.Core
LIB_MCS_FLAGS = /unsafe
-TEST_MCS_FLAGS = /r:System /r:System.Core
+TEST_MCS_FLAGS = /r:System.dll /r:System.Core.dll
include ../../build/library.make
--- /dev/null
+using System;
+using System.Reflection;
+
+[assembly:System.Runtime.CompilerServices.InternalsVisibleTo ("Xamarin.Mac, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
+
+namespace System.Net.Http {
+ public partial class HttpClient {
+
+ public HttpClient ()
+ : this (GetDefaultHandler (), true)
+ {
+ }
+
+ // note: the linker will re-write ObjCRuntime.RuntimeOptions.GetHttpMessageHandler to return the correct type
+ // unlike, XI where this method itself gets rewritten during linking
+ static HttpMessageHandler GetDefaultHandler ()
+ {
+ Type type = Type.GetType("ObjCRuntime.RuntimeOptions, Xamarin.Mac");
+ var method = type.GetMethod ("GetHttpMessageHandler", BindingFlags.Static | BindingFlags.NonPublic);
+ return (HttpMessageHandler)method.Invoke (null, null);
+ }
+ }
+}
const int WaitTimeout = 5000;
- string port, TestHost, LocalServer;
+ string TestHost, LocalServer;
+ int port;
[SetUp]
public void SetupFixture ()
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
- port = "810";
+ port = 810;
} else {
- port = "8810";
+ port = 8810;
}
TestHost = "localhost:" + port;
var response = l.Response;
response.StatusCode = (int)HttpStatusCode.Moved;
- response.RedirectLocation = "http://xamarin.com/";
+ response.RedirectLocation = "http://localhost:8811/";
});
+ var listener2 = CreateListener (l => {
+ var response = l.Response;
+
+ response.StatusCode = (int)HttpStatusCode.OK;
+ response.OutputStream.WriteByte (0x68);
+ response.OutputStream.WriteByte (0x65);
+ response.OutputStream.WriteByte (0x6c);
+ response.OutputStream.WriteByte (0x6c);
+ response.OutputStream.WriteByte (0x6f);
+ }, 8811);
+
try {
var chandler = new HttpClientHandler ();
chandler.AllowAutoRedirect = true;
var r = client.GetAsync (LocalServer);
Assert.IsTrue (r.Wait (WaitTimeout), "#1");
var resp = r.Result;
- Assert.AreEqual ("http://xamarin.com/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
+ Assert.AreEqual ("http://localhost:8811/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
+ Assert.AreEqual ("hello", resp.Content.ReadAsStringAsync ().Result, "#3");
} finally {
listener.Abort ();
listener.Close ();
+ listener2.Abort ();
+ listener2.Close ();
}
}
}
HttpListener CreateListener (Action<HttpListenerContext> contextAssert)
+ {
+ return CreateListener (contextAssert, port);
+ }
+
+ HttpListener CreateListener (Action<HttpListenerContext> contextAssert, int port)
{
var l = new HttpListener ();
l.Prefixes.Add (string.Format ("http://+:{0}/", port));
#include System.Net.Http.dll.sources
+System.Net.Http/HttpClient.mac.cs
#include System.Net.Http.dll.sources
+System.Net.Http/HttpClient.mac.cs
LIBRARY = System.Runtime.Remoting.dll
-LIB_REFS = System System.Web System.Xml System.Runtime.Serialization.Formatters.Soap
+LIB_REFS = System System.Xml System.Runtime.Serialization.Formatters.Soap
LIB_MCS_FLAGS = /r:$(corlib)
+ifndef NO_SYSTEM_WEB_DEPENDENCY
+LIB_REFS += System.Web
+endif
+
TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -nowarn:618 /r:System.Runtime.Remoting.dll
TEST_MONO_PATH = .
--- /dev/null
+Assembly/AssemblyInfo.cs
+../../build/common/Consts.cs
+../../build/common/Locale.cs
+../../build/common/MonoTODOAttribute.cs
+System.Runtime.Remoting.Channels/BinaryClientFormatterSink.cs
+System.Runtime.Remoting.Channels/BinaryClientFormatterSinkProvider.cs
+System.Runtime.Remoting.Channels/BinaryCore.cs
+System.Runtime.Remoting.Channels/BinaryServerFormatterSink.cs
+System.Runtime.Remoting.Channels/BinaryServerFormatterSinkProvider.cs
+System.Runtime.Remoting.Channels/ChannelCore.cs
+System.Runtime.Remoting.Channels/CommonTransportKeys.cs
+System.Runtime.Remoting.Channels/IAuthorizeRemotingConnection.cs
+System.Runtime.Remoting.Channels/RemotingThreadPool.cs
+System.Runtime.Remoting.Channels/SoapClientFormatterSink.cs
+System.Runtime.Remoting.Channels/SoapCore.cs
+System.Runtime.Remoting.Channels/SoapServerFormatterSink.cs
+System.Runtime.Remoting.Channels/SoapClientFormatterSinkProvider.cs
+System.Runtime.Remoting.Channels/SoapServerFormatterSinkProvider.cs
+System.Runtime.Remoting.Channels/SoapMessageFormatter.cs
+System.Runtime.Remoting.Channels/SocketCachePolicy.cs
+System.Runtime.Remoting.Channels.Ipc/IpcChannel.cs
+System.Runtime.Remoting.Channels.Ipc/IpcClientChannel.cs
+System.Runtime.Remoting.Channels.Ipc/IpcServerChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcTransport.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannelHelper.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcClientChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcServerChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeClient.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeException.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeHelper.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeListener.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeStream.cs
+System.Runtime.Remoting.Channels.Ipc.Unix/IpcChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Unix/IpcClientChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Unix/IpcServerChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Unix/UnixChannelLoader.cs
+System.Runtime.Remoting.Channels.Tcp/TcpChannel.cs
+System.Runtime.Remoting.Channels.Tcp/TcpClientChannel.cs
+System.Runtime.Remoting.Channels.Tcp/TcpMessageIO.cs
+System.Runtime.Remoting.Channels.Tcp/TcpServerChannel.cs
+System.Runtime.Remoting.Channels.Tcp/TcpServerTransportSink.cs
+System.Runtime.Remoting.Channels.Tcp/TcpClientTransportSinkProvider.cs
+System.Runtime.Remoting.Channels.Tcp/TcpClientTransportSink.cs
+System.Runtime.Remoting.Channels.Tcp/TcpConnectionPool.cs
+System.Runtime.Remoting.MetadataServices/MetaData.cs
+System.Runtime.Remoting.MetadataServices/MetaDataExporter.cs
+System.Runtime.Remoting.MetadataServices/MetaDataCodeGenerator.cs
+System.Runtime.Remoting.MetadataServices/SdlChannelSinkProvider.cs
+System.Runtime.Remoting.MetadataServices/ServiceType.cs
+System.Runtime.Remoting.MetadataServices/SUDSParserException.cs
+System.Runtime.Remoting.MetadataServices/SdlChannelSink.cs
+System.Runtime.Remoting.MetadataServices/SdlType.cs
+System.Runtime.Remoting.MetadataServices/SUDSGeneratorException.cs
+System.Runtime.Remoting.Services/RemotingClientProxy.cs
} else {
var typeHandleValue = Type.GetTypeHandle (memberValue);
var isDeclaredType = typeHandleValue.Equals (CodeInterpreter.ConvertValue (memberValue, memberType, Globals.TypeOfObject));
- if (isNullableOfT)
+ if (isNullableOfT) {
ctx.InternalSerialize (writer, memberValue, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle);
- else
- ctx.InternalSerializeReference (writer, memberValue, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle);
- //InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod), () => memberValue, memberType, writeXsiType);
+ } else if (memberType == Globals.TypeOfObject) {
+ var dataContract = DataContract.GetDataContract (memberValue.GetType());
+ writer.WriteAttributeQualifiedName (Globals.XsiPrefix, DictionaryGlobals.XsiTypeLocalName, DictionaryGlobals.SchemaInstanceNamespace, dataContract.Name, dataContract.Namespace);
+ ctx.InternalSerializeReference (writer, memberValue, false, false, -1, typeHandleValue);
+ } else {
+ ctx.InternalSerializeReference (writer, memberValue, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle);
+ }
}
}
}
Assert.IsTrue (s.Contains ("<Flags>All</Flags>"));
}
}
+
+ // Bug #37116
+ [Test]
+ public void KeyPairOfAny ()
+ {
+ var dict = new Dictionary<string, object> ();
+ dict.Add ("test", new List<string> () { "test entry" });
+
+ var dcs = new DataContractSerializer (typeof(Dictionary<string, object>));
+ dcs.WriteObject (new MemoryStream (), dict);
+ // Should not throw exception.
+ }
}
}
return new EndpointAddress10 (address);
}
-#if !NET_2_1
public static XmlQualifiedName GetSchema (XmlSchemaSet xmlSchemaSet)
{
if (xmlSchemaSet == null)
xmlSchemaSet.Add (XmlSchema.Read (typeof (EndpointAddress10).Assembly.GetManifestResourceStream ("ws-addr.xsd"), null));
return new XmlQualifiedName ("EndpointReferenceType", AddressingVersion.WSAddressing10.Namespace);
}
-#endif
public EndpointAddress ToEndpointAddress ()
{
System.ServiceModel.Security/TransportSecurityBindingElementTest.cs
System.ServiceModel.Security/WSSecurityTokenSerializerTest.cs
System.ServiceModel/BasicHttpBindingTest.cs
+System.ServiceModel/Bug36080Test.cs
System.ServiceModel/CallbackBehaviorAttributeTest.cs
System.ServiceModel/ChannelFactoryTest.cs
System.ServiceModel/ChannelFactory_1Test.cs
--- /dev/null
+//
+// Author:
+// Marcos Henrich <marcos.henrich@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// 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.
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.ServiceModel;
+using System.ServiceModel.Description;
+using System.Threading;
+using System.ServiceModel.Channels;
+using System.Text;
+using NUnit.Framework;
+
+using MonoTests.Helpers;
+
+namespace MonoTests.System.ServiceModel
+{
+ [TestFixture]
+ public class Bug36080
+ {
+ [Test]
+ public void Bug36080Test ()
+ {
+ int port = NetworkHelpers.FindFreePort ();
+ var url = "http://localhost:" + port + "/HelloWorldService";
+
+ TransportBindingElement element = new HttpTransportBindingElement { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
+ Binding binding = new CustomBinding(new BindingElement[]
+ {
+ new TextMessageEncodingBindingElement (MessageVersion.Default, Encoding.UTF8),
+ element
+ });
+
+#if !MOBILE
+ // Init service
+ ServiceHost serviceHost = new ServiceHost (typeof (HelloWorldServiceImpl), new Uri (url));
+ serviceHost.AddServiceEndpoint (typeof (IHelloWorldService), binding, string.Empty);
+
+ serviceHost.Open ();
+#endif
+ // In Mobile we still run this tests without any server.
+ // Issue reported in #36080 was occuring before the connections fails.
+ var wait = new ManualResetEvent (false);
+
+ Exception error = null;
+ string result = null;
+
+ try {
+ var client = new HelloWorldServiceClient (binding, new EndpointAddress(url));
+ client.SayHelloToCompleted += delegate (object o, SayHelloToCompletedEventArgs e) {
+ try {
+ error = e.Error;
+ result = e.Error == null ? e.Result : null;
+ } finally {
+ wait.Set ();
+ }
+ };
+
+ var str = "Xamarin";
+ client.SayHelloToAsync(str);
+
+ Assert.IsTrue (wait.WaitOne (TimeSpan.FromSeconds (20)), "timeout");
+#if MOBILE
+ if (error.GetType() == typeof(EndpointNotFoundException))
+ return;
+#endif
+
+ Assert.IsNull (error, "#1, inner exception: {0}", error);
+ Assert.AreEqual (str, result, "#2");
+ } finally {
+#if !MOBILE
+ serviceHost.Close ();
+#endif
+ }
+ }
+ }
+
+ public class HelloWorldServiceImpl : IHelloWorldService
+ {
+ Func<string, string> sayHelloToFunc = SayHelloTo;
+
+ static string SayHelloTo (string name)
+ {
+ return name;
+ }
+
+ public IAsyncResult BeginSayHelloTo(string name, AsyncCallback callback, object asyncState)
+ {
+ return sayHelloToFunc.BeginInvoke (name, callback, asyncState);
+ }
+
+ public string EndSayHelloTo(IAsyncResult result)
+ {
+ return sayHelloToFunc.EndInvoke(result);
+ }
+
+ public IAsyncResult BeginGetHelloData(TestXamarin4WCFService.HelloWorldData helloWorldData, AsyncCallback callback, object asyncState)
+ {
+ return null;
+ }
+
+ public TestXamarin4WCFService.HelloWorldData EndGetHelloData(IAsyncResult result)
+ {
+ return null;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.18444
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+//
+// This code was auto-generated by SlSvcUtil, version 5.0.61118.0
+//
+namespace TestXamarin4WCFService
+{
+ using System.Runtime.Serialization;
+
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
+ [System.Runtime.Serialization.DataContractAttribute(Name = "HelloWorldData", Namespace = "http://schemas.datacontract.org/2004/07/TestXamarin4WCFService")]
+ public partial class HelloWorldData : object
+ {
+
+ private string NameField;
+
+ private bool SayHelloField;
+
+ [System.Runtime.Serialization.DataMemberAttribute()]
+ public string Name
+ {
+ get
+ {
+ return this.NameField;
+ }
+ set
+ {
+ this.NameField = value;
+ }
+ }
+
+ [System.Runtime.Serialization.DataMemberAttribute()]
+ public bool SayHello
+ {
+ get
+ {
+ return this.SayHelloField;
+ }
+ set
+ {
+ this.SayHelloField = value;
+ }
+ }
+ }
+}
+
+
+[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+[System.ServiceModel.ServiceContractAttribute(ConfigurationName="IHelloWorldService")]
+public interface IHelloWorldService
+{
+
+ [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IHelloWorldService/SayHelloTo", ReplyAction="http://tempuri.org/IHelloWorldService/SayHelloToResponse")]
+ System.IAsyncResult BeginSayHelloTo(string name, System.AsyncCallback callback, object asyncState);
+
+ string EndSayHelloTo(System.IAsyncResult result);
+
+ [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IHelloWorldService/GetHelloData", ReplyAction="http://tempuri.org/IHelloWorldService/GetHelloDataResponse")]
+ System.IAsyncResult BeginGetHelloData(TestXamarin4WCFService.HelloWorldData helloWorldData, System.AsyncCallback callback, object asyncState);
+
+ TestXamarin4WCFService.HelloWorldData EndGetHelloData(System.IAsyncResult result);
+}
+
+[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+public interface IHelloWorldServiceChannel : IHelloWorldService, System.ServiceModel.IClientChannel
+{
+}
+
+[System.Diagnostics.DebuggerStepThroughAttribute()]
+[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+public partial class SayHelloToCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
+{
+
+ private object[] results;
+
+ public SayHelloToCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState)
+ {
+ this.results = results;
+ }
+
+ public string Result
+ {
+ get
+ {
+ base.RaiseExceptionIfNecessary();
+ return ((string)(this.results[0]));
+ }
+ }
+}
+
+[System.Diagnostics.DebuggerStepThroughAttribute()]
+[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+public partial class GetHelloDataCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
+{
+
+ private object[] results;
+
+ public GetHelloDataCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState)
+ {
+ this.results = results;
+ }
+
+ public TestXamarin4WCFService.HelloWorldData Result
+ {
+ get
+ {
+ base.RaiseExceptionIfNecessary();
+ return ((TestXamarin4WCFService.HelloWorldData)(this.results[0]));
+ }
+ }
+}
+
+[System.Diagnostics.DebuggerStepThroughAttribute()]
+[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
+public partial class HelloWorldServiceClient : System.ServiceModel.ClientBase<IHelloWorldService>, IHelloWorldService
+{
+
+ private BeginOperationDelegate onBeginSayHelloToDelegate;
+
+ private EndOperationDelegate onEndSayHelloToDelegate;
+
+ private System.Threading.SendOrPostCallback onSayHelloToCompletedDelegate;
+
+ private BeginOperationDelegate onBeginGetHelloDataDelegate;
+
+ private EndOperationDelegate onEndGetHelloDataDelegate;
+
+ private System.Threading.SendOrPostCallback onGetHelloDataCompletedDelegate;
+
+ private BeginOperationDelegate onBeginOpenDelegate;
+
+ private EndOperationDelegate onEndOpenDelegate;
+
+ private System.Threading.SendOrPostCallback onOpenCompletedDelegate;
+
+ private BeginOperationDelegate onBeginCloseDelegate;
+
+ private EndOperationDelegate onEndCloseDelegate;
+
+ private System.Threading.SendOrPostCallback onCloseCompletedDelegate;
+
+ public HelloWorldServiceClient()
+ {
+ }
+
+ public HelloWorldServiceClient(string endpointConfigurationName) :
+ base(endpointConfigurationName)
+ {
+ }
+
+ public HelloWorldServiceClient(string endpointConfigurationName, string remoteAddress) :
+ base(endpointConfigurationName, remoteAddress)
+ {
+ }
+
+ public HelloWorldServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
+ base(endpointConfigurationName, remoteAddress)
+ {
+ }
+
+ public HelloWorldServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
+ base(binding, remoteAddress)
+ {
+ }
+
+ public System.Net.CookieContainer CookieContainer
+ {
+ get
+ {
+ System.ServiceModel.Channels.IHttpCookieContainerManager httpCookieContainerManager = this.InnerChannel.GetProperty<System.ServiceModel.Channels.IHttpCookieContainerManager>();
+ if ((httpCookieContainerManager != null))
+ {
+ return httpCookieContainerManager.CookieContainer;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ set
+ {
+ System.ServiceModel.Channels.IHttpCookieContainerManager httpCookieContainerManager = this.InnerChannel.GetProperty<System.ServiceModel.Channels.IHttpCookieContainerManager>();
+ if ((httpCookieContainerManager != null))
+ {
+ httpCookieContainerManager.CookieContainer = value;
+ }
+ else
+ {
+ throw new System.InvalidOperationException("Unable to set the CookieContainer. Please make sure the binding contains an HttpC" +
+ "ookieContainerBindingElement.");
+ }
+ }
+ }
+
+ public event System.EventHandler<SayHelloToCompletedEventArgs> SayHelloToCompleted;
+
+ public event System.EventHandler<GetHelloDataCompletedEventArgs> GetHelloDataCompleted;
+
+ public event System.EventHandler<System.ComponentModel.AsyncCompletedEventArgs> OpenCompleted;
+
+ public event System.EventHandler<System.ComponentModel.AsyncCompletedEventArgs> CloseCompleted;
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ System.IAsyncResult IHelloWorldService.BeginSayHelloTo(string name, System.AsyncCallback callback, object asyncState)
+ {
+ return base.Channel.BeginSayHelloTo(name, callback, asyncState);
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ string IHelloWorldService.EndSayHelloTo(System.IAsyncResult result)
+ {
+ return base.Channel.EndSayHelloTo(result);
+ }
+
+ private System.IAsyncResult OnBeginSayHelloTo(object[] inValues, System.AsyncCallback callback, object asyncState)
+ {
+ string name = ((string)(inValues[0]));
+ return ((IHelloWorldService)(this)).BeginSayHelloTo(name, callback, asyncState);
+ }
+
+ private object[] OnEndSayHelloTo(System.IAsyncResult result)
+ {
+ string retVal = ((IHelloWorldService)(this)).EndSayHelloTo(result);
+ return new object[] {
+ retVal};
+ }
+
+ private void OnSayHelloToCompleted(object state)
+ {
+ if ((this.SayHelloToCompleted != null))
+ {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.SayHelloToCompleted(this, new SayHelloToCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void SayHelloToAsync(string name)
+ {
+ this.SayHelloToAsync(name, null);
+ }
+
+ public void SayHelloToAsync(string name, object userState)
+ {
+ if ((this.onBeginSayHelloToDelegate == null))
+ {
+ this.onBeginSayHelloToDelegate = new BeginOperationDelegate(this.OnBeginSayHelloTo);
+ }
+ if ((this.onEndSayHelloToDelegate == null))
+ {
+ this.onEndSayHelloToDelegate = new EndOperationDelegate(this.OnEndSayHelloTo);
+ }
+ if ((this.onSayHelloToCompletedDelegate == null))
+ {
+ this.onSayHelloToCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnSayHelloToCompleted);
+ }
+ base.InvokeAsync(this.onBeginSayHelloToDelegate, new object[] {
+ name}, this.onEndSayHelloToDelegate, this.onSayHelloToCompletedDelegate, userState);
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ System.IAsyncResult IHelloWorldService.BeginGetHelloData(TestXamarin4WCFService.HelloWorldData helloWorldData, System.AsyncCallback callback, object asyncState)
+ {
+ return base.Channel.BeginGetHelloData(helloWorldData, callback, asyncState);
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ TestXamarin4WCFService.HelloWorldData IHelloWorldService.EndGetHelloData(System.IAsyncResult result)
+ {
+ return base.Channel.EndGetHelloData(result);
+ }
+
+ private System.IAsyncResult OnBeginGetHelloData(object[] inValues, System.AsyncCallback callback, object asyncState)
+ {
+ TestXamarin4WCFService.HelloWorldData helloWorldData = ((TestXamarin4WCFService.HelloWorldData)(inValues[0]));
+ return ((IHelloWorldService)(this)).BeginGetHelloData(helloWorldData, callback, asyncState);
+ }
+
+ private object[] OnEndGetHelloData(System.IAsyncResult result)
+ {
+ TestXamarin4WCFService.HelloWorldData retVal = ((IHelloWorldService)(this)).EndGetHelloData(result);
+ return new object[] {
+ retVal};
+ }
+
+ private void OnGetHelloDataCompleted(object state)
+ {
+ if ((this.GetHelloDataCompleted != null))
+ {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.GetHelloDataCompleted(this, new GetHelloDataCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void GetHelloDataAsync(TestXamarin4WCFService.HelloWorldData helloWorldData)
+ {
+ this.GetHelloDataAsync(helloWorldData, null);
+ }
+
+ public void GetHelloDataAsync(TestXamarin4WCFService.HelloWorldData helloWorldData, object userState)
+ {
+ if ((this.onBeginGetHelloDataDelegate == null))
+ {
+ this.onBeginGetHelloDataDelegate = new BeginOperationDelegate(this.OnBeginGetHelloData);
+ }
+ if ((this.onEndGetHelloDataDelegate == null))
+ {
+ this.onEndGetHelloDataDelegate = new EndOperationDelegate(this.OnEndGetHelloData);
+ }
+ if ((this.onGetHelloDataCompletedDelegate == null))
+ {
+ this.onGetHelloDataCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnGetHelloDataCompleted);
+ }
+ base.InvokeAsync(this.onBeginGetHelloDataDelegate, new object[] {
+ helloWorldData}, this.onEndGetHelloDataDelegate, this.onGetHelloDataCompletedDelegate, userState);
+ }
+
+ private System.IAsyncResult OnBeginOpen(object[] inValues, System.AsyncCallback callback, object asyncState)
+ {
+ return ((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(callback, asyncState);
+ }
+
+ private object[] OnEndOpen(System.IAsyncResult result)
+ {
+ ((System.ServiceModel.ICommunicationObject)(this)).EndOpen(result);
+ return null;
+ }
+
+ private void OnOpenCompleted(object state)
+ {
+ if ((this.OpenCompleted != null))
+ {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.OpenCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void OpenAsync()
+ {
+ this.OpenAsync(null);
+ }
+
+ public void OpenAsync(object userState)
+ {
+ if ((this.onBeginOpenDelegate == null))
+ {
+ this.onBeginOpenDelegate = new BeginOperationDelegate(this.OnBeginOpen);
+ }
+ if ((this.onEndOpenDelegate == null))
+ {
+ this.onEndOpenDelegate = new EndOperationDelegate(this.OnEndOpen);
+ }
+ if ((this.onOpenCompletedDelegate == null))
+ {
+ this.onOpenCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnOpenCompleted);
+ }
+ base.InvokeAsync(this.onBeginOpenDelegate, null, this.onEndOpenDelegate, this.onOpenCompletedDelegate, userState);
+ }
+
+ private System.IAsyncResult OnBeginClose(object[] inValues, System.AsyncCallback callback, object asyncState)
+ {
+ return ((System.ServiceModel.ICommunicationObject)(this)).BeginClose(callback, asyncState);
+ }
+
+ private object[] OnEndClose(System.IAsyncResult result)
+ {
+ ((System.ServiceModel.ICommunicationObject)(this)).EndClose(result);
+ return null;
+ }
+
+ private void OnCloseCompleted(object state)
+ {
+ if ((this.CloseCompleted != null))
+ {
+ InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
+ this.CloseCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
+ }
+ }
+
+ public void CloseAsync()
+ {
+ this.CloseAsync(null);
+ }
+
+ public void CloseAsync(object userState)
+ {
+ if ((this.onBeginCloseDelegate == null))
+ {
+ this.onBeginCloseDelegate = new BeginOperationDelegate(this.OnBeginClose);
+ }
+ if ((this.onEndCloseDelegate == null))
+ {
+ this.onEndCloseDelegate = new EndOperationDelegate(this.OnEndClose);
+ }
+ if ((this.onCloseCompletedDelegate == null))
+ {
+ this.onCloseCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnCloseCompleted);
+ }
+ base.InvokeAsync(this.onBeginCloseDelegate, null, this.onEndCloseDelegate, this.onCloseCompletedDelegate, userState);
+ }
+
+ protected override IHelloWorldService CreateChannel()
+ {
+ return new HelloWorldServiceClientChannel(this);
+ }
+
+ private class HelloWorldServiceClientChannel : ChannelBase<IHelloWorldService>, IHelloWorldService
+ {
+
+ public HelloWorldServiceClientChannel(System.ServiceModel.ClientBase<IHelloWorldService> client) :
+ base(client)
+ {
+ }
+
+ public System.IAsyncResult BeginSayHelloTo(string name, System.AsyncCallback callback, object asyncState)
+ {
+ object[] _args = new object[1];
+ _args[0] = name;
+ System.IAsyncResult _result = base.BeginInvoke("SayHelloTo", _args, callback, asyncState);
+ return _result;
+ }
+
+ public string EndSayHelloTo(System.IAsyncResult result)
+ {
+ object[] _args = new object[0];
+ string _result = ((string)(base.EndInvoke("SayHelloTo", _args, result)));
+ return _result;
+ }
+
+ public System.IAsyncResult BeginGetHelloData(TestXamarin4WCFService.HelloWorldData helloWorldData, System.AsyncCallback callback, object asyncState)
+ {
+ object[] _args = new object[1];
+ _args[0] = helloWorldData;
+ System.IAsyncResult _result = base.BeginInvoke("GetHelloData", _args, callback, asyncState);
+ return _result;
+ }
+
+ public TestXamarin4WCFService.HelloWorldData EndGetHelloData(System.IAsyncResult result)
+ {
+ object[] _args = new object[0];
+ TestXamarin4WCFService.HelloWorldData _result = ((TestXamarin4WCFService.HelloWorldData)(base.EndInvoke("GetHelloData", _args, result)));
+ return _result;
+ }
+ }
+}
if (!hashAlg.CanReuseTransform) {
canReuseHashAlg = false;
hashAlg = null;
+ return null;
}
+ hashAlg.Key = MachineKeySectionUtils.GetValidationKey (mks);
}
if (hashAlg != null)
--- /dev/null
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo ("monotouch, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
+[assembly: InternalsVisibleTo ("Xamarin.iOS, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
+[assembly: InternalsVisibleTo ("Xamarin.Mac, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
+[assembly: InternalsVisibleTo ("Xamarin.WatchOS, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
+[assembly: InternalsVisibleTo ("Xamarin.TVOS, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
if (provider != null && provider.HasCustomSystemCertificateValidator) {
var xerrors = (MonoSslPolicyErrors)errors;
var xchain = (XX509Chain)(object)chain;
- providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, xchain, out result, ref xerrors, ref status11);
+ providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, ref xchain, out result, ref xerrors, ref status11);
+ chain = (X509Chain)(object)xchain;
errors = (SslPolicyErrors)xerrors;
}
+++ /dev/null
-#if MONOTOUCH || XAMMAC
-
-// this file is a shim to enable compiling monotouch profiles without mono-extensions
-namespace Mono.Net.Security
-{
- static partial class MonoTlsProviderFactory
- {
- static IMonoTlsProvider CreateDefaultProvider ()
- {
- throw new System.NotSupportedException ();
- }
- }
-}
-
-#endif
--- /dev/null
+// Copyright 2015 Xamarin Inc. All rights reserved.
+
+using System;
+using MSI = Mono.Security.Interface;
+
+namespace Mono.Net.Security
+{
+ static partial class MonoTlsProviderFactory
+ {
+ static IMonoTlsProvider CreateDefaultProvider ()
+ {
+ #if SECURITY_DEP
+ MSI.MonoTlsProvider provider = null;
+ if (MSI.MonoTlsProviderFactory._PrivateFactoryDelegate != null)
+ provider = MSI.MonoTlsProviderFactory._PrivateFactoryDelegate ();
+ if (provider != null)
+ return new Private.MonoTlsProviderWrapper (provider);
+ #endif
+ return null;
+ }
+ }
+}
static bool CheckUsage (XX509CertificateCollection certs, string host, ref SslPolicyErrors errors, ref int status11)
{
#if !MONOTOUCH
- var leaf = (X509Certificate2)certs[0];
+ var leaf = certs[0] as X509Certificate2;
+ if (leaf == null)
+ leaf = new X509Certificate2 (certs[0]);
// for OSX and iOS we're using the native API to check for the SSL server policy and host names
if (!is_macosx) {
if (!CheckCertificateUsage (leaf)) {
--- /dev/null
+namespace Mono.Security.Interface
+{
+ public delegate MonoTlsProvider MonoTlsProviderFactoryDelegate ();
+
+ static partial class MonoTlsProviderFactory
+ {
+ public static MonoTlsProviderFactoryDelegate _PrivateFactoryDelegate;
+ }
+}
WritePrefix ();
}
- WriteDebugString (message);
-
if (Debugger.IsLogging())
Debugger.Log (0, null, message);
+ else
+ WriteDebugString (message);
WriteLogFile (message, LogFileName);
}
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The session ID for this process.")]
public int SessionId {
- get { throw new NotImplementedException (); }
+ get { return 0; }
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
sealed class SafeSocketHandle : SafeHandleZeroOrMinusOneIsInvalid {
List<Thread> blocking_threads;
+ bool in_cleanup;
const int SOCKET_CLOSED = 10004;
#endif
if (blocking_threads != null) {
- int abort_attempts = 0;
- while (blocking_threads.Count > 0) {
- if (abort_attempts++ >= ABORT_RETRIES) {
- if (THROW_ON_ABORT_RETRIES)
- throw new Exception ("Could not abort registered blocking threads before closing socket.");
-
- // Attempts to close the socket safely failed.
- // We give up, and close the socket with pending blocking system calls.
- // This should not occur, nonetheless if it does this avoids an endless loop.
- break;
- }
-
- /*
- * This method can be called by the DangerousRelease inside RegisterForBlockingSyscall
- * When this happens blocking_threads contains the current thread.
- * We can safely close the socket and throw SocketException in RegisterForBlockingSyscall
- * before the blocking system call.
- */
- lock (blocking_threads) {
+ lock (blocking_threads) {
+ int abort_attempts = 0;
+ while (blocking_threads.Count > 0) {
+ if (abort_attempts++ >= ABORT_RETRIES) {
+ if (THROW_ON_ABORT_RETRIES)
+ throw new Exception ("Could not abort registered blocking threads before closing socket.");
+
+ // Attempts to close the socket safely failed.
+ // We give up, and close the socket with pending blocking system calls.
+ // This should not occur, nonetheless if it does this avoids an endless loop.
+ break;
+ }
+
+ /*
+ * This method can be called by the DangerousRelease inside RegisterForBlockingSyscall
+ * When this happens blocking_threads contains the current thread.
+ * We can safely close the socket and throw SocketException in RegisterForBlockingSyscall
+ * before the blocking system call.
+ */
if (blocking_threads.Count == 1 && blocking_threads[0] == Thread.CurrentThread)
break;
- }
- AbortRegisteredThreads ();
- // Sleep so other threads can resume
- Thread.Sleep (1);
+ // abort registered threads
+ foreach (var t in blocking_threads)
+ Socket.cancel_blocking_socket_operation (t);
+
+ // Sleep so other threads can resume
+ in_cleanup = true;
+ Monitor.Wait (blocking_threads, 100);
+ }
}
}
//If this NRE, we're in deep problems because Register Must have
lock (blocking_threads) {
blocking_threads.Remove (Thread.CurrentThread);
- }
- }
-
- void AbortRegisteredThreads () {
- if (blocking_threads == null)
- return;
-
- lock (blocking_threads) {
- foreach (var t in blocking_threads)
- Socket.cancel_blocking_socket_operation (t);
+ if (in_cleanup && blocking_threads.Count == 0)
+ Monitor.Pulse (blocking_threads);
}
}
}
}
public bool IsLocal {
- get { return IPAddress.IsLoopback (RemoteEndPoint.Address); }
+ get { return LocalEndPoint.Address.Equals (RemoteEndPoint.Address); }
}
public bool IsSecureConnection {
X500DistinguishedNameFlags.UseT61Encoding | X500DistinguishedNameFlags.ForceUTF8Encoding;
private string name;
+ private byte[] canonEncoding;
public X500DistinguishedName (AsnEncodedData encodedDistinguishedName)
name = distinguishedName.name;
}
+ internal X500DistinguishedName (byte[] encoded, byte[] canonEncoding, string name)
+ : this (encoded)
+ {
+ this.canonEncoding = canonEncoding;
+ this.name = name;
+
+ Oid = new Oid ();
+ RawData = encoded;
+ }
+
+ internal byte[] CanonicalEncoding {
+ get { return canonEncoding; }
+ }
+
public string Name {
get { return name; }
if (name2 == null)
return false;
+ if (name1.canonEncoding != null && name2.canonEncoding != null) {
+ if (name1.canonEncoding.Length != name2.canonEncoding.Length)
+ return false;
+ for (int i = 0; i < name1.canonEncoding.Length; i++) {
+ if (name1.canonEncoding[i] != name2.canonEncoding[2])
+ return false;
+ }
+ return true;
+ }
+
X500DistinguishedNameFlags flags = X500DistinguishedNameFlags.UseNewLines | X500DistinguishedNameFlags.DoNotUseQuotes;
string[] split = new string[] { Environment.NewLine };
string[] parts1 = name1.Decode (flags).Split (split, StringSplitOptions.RemoveEmptyEntries);
using System.IO;
using System.Text;
+using System.Collections;
namespace System.Security.Cryptography.X509Certificates {
[Serializable]
public class X509Certificate2 : X509Certificate {
+
#if !SECURITY_DEP
// Used in Mono.Security HttpsClientStream
public X509Certificate2 (byte[] rawData)
}
#endif
#if SECURITY_DEP
- private bool _archived;
- private X509ExtensionCollection _extensions;
- private string _name = String.Empty;
- private string _serial;
- private PublicKey _publicKey;
- private X500DistinguishedName issuer_name;
- private X500DistinguishedName subject_name;
- private Oid signature_algorithm;
-
- private MX.X509Certificate _cert;
+ new internal X509Certificate2Impl Impl {
+ get {
+ var impl2 = base.Impl as X509Certificate2Impl;
+ X509Helper2.ThrowIfContextInvalid (impl2);
+ return impl2;
+ }
+ }
- private static string empty_error = Locale.GetText ("Certificate instance is empty.");
+ string friendlyName = string.Empty;
// constructors
public X509Certificate2 ()
{
- _cert = null;
}
public X509Certificate2 (byte[] rawData)
public X509Certificate2 (IntPtr handle) : base (handle)
{
- _cert = new MX.X509Certificate (base.GetRawCertData ());
+ throw new NotImplementedException ();
}
public X509Certificate2 (X509Certificate certificate)
- : base (certificate)
+ : base (X509Helper2.Import (certificate))
+ {
+ }
+
+ internal X509Certificate2 (X509Certificate2Impl impl)
+ : base (impl)
{
- _cert = new MX.X509Certificate (base.GetRawCertData ());
}
// properties
public bool Archived {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _archived;
- }
- set {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- _archived = value;
- }
+ get { return Impl.Archived; }
+ set { Impl.Archived = true; }
}
public X509ExtensionCollection Extensions {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- if (_extensions == null)
- _extensions = new X509ExtensionCollection (_cert);
- return _extensions;
- }
+ get { return Impl.Extensions; }
}
public string FriendlyName {
get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _name;
+ ThrowIfContextInvalid ();
+ return friendlyName;
}
set {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- _name = value;
+ ThrowIfContextInvalid ();
+ friendlyName = value;
}
}
- // FIXME - Could be more efficient
public bool HasPrivateKey {
- get { return PrivateKey != null; }
+ get { return Impl.HasPrivateKey; }
}
public X500DistinguishedName IssuerName {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- if (issuer_name == null)
- issuer_name = new X500DistinguishedName (_cert.GetIssuerName ().GetBytes ());
- return issuer_name;
- }
+ get { return Impl.IssuerName; }
}
public DateTime NotAfter {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _cert.ValidUntil.ToLocalTime ();
- }
+ get { return Impl.GetValidUntil ().ToLocalTime (); }
}
public DateTime NotBefore {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _cert.ValidFrom.ToLocalTime ();
- }
+ get { return Impl.GetValidFrom ().ToLocalTime (); }
}
public AsymmetricAlgorithm PrivateKey {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- try {
- if (_cert.RSA != null) {
- RSACryptoServiceProvider rcsp = _cert.RSA as RSACryptoServiceProvider;
- if (rcsp != null)
- return rcsp.PublicOnly ? null : rcsp;
-
- RSAManaged rsam = _cert.RSA as RSAManaged;
- if (rsam != null)
- return rsam.PublicOnly ? null : rsam;
-
- _cert.RSA.ExportParameters (true);
- return _cert.RSA;
- } else if (_cert.DSA != null) {
- DSACryptoServiceProvider dcsp = _cert.DSA as DSACryptoServiceProvider;
- if (dcsp != null)
- return dcsp.PublicOnly ? null : dcsp;
-
- _cert.DSA.ExportParameters (true);
- return _cert.DSA;
- }
- }
- catch {
- }
- return null;
- }
- set {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- // allow NULL so we can "forget" the key associated to the certificate
- // e.g. in case we want to export it in another format (see bug #396620)
- if (value == null) {
- _cert.RSA = null;
- _cert.DSA = null;
- } else if (value is RSA)
- _cert.RSA = (RSA) value;
- else if (value is DSA)
- _cert.DSA = (DSA) value;
- else
- throw new NotSupportedException ();
- }
+ get { return Impl.PrivateKey; }
+ set { Impl.PrivateKey = value; }
}
public PublicKey PublicKey {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- if (_publicKey == null) {
- try {
- _publicKey = new PublicKey (_cert);
- }
- catch (Exception e) {
- string msg = Locale.GetText ("Unable to decode public key.");
- throw new CryptographicException (msg, e);
- }
- }
- return _publicKey;
- }
+ get { return Impl.PublicKey; }
}
public byte[] RawData {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- return base.GetRawCertData ();
- }
- }
+ get { return GetRawCertData (); }
+ }
public string SerialNumber {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- if (_serial == null) {
- StringBuilder sb = new StringBuilder ();
- byte[] serial = _cert.SerialNumber;
- for (int i=serial.Length - 1; i >= 0; i--)
- sb.Append (serial [i].ToString ("X2"));
- _serial = sb.ToString ();
- }
- return _serial;
- }
+ get { return GetSerialNumberString (); }
}
public Oid SignatureAlgorithm {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- if (signature_algorithm == null)
- signature_algorithm = new Oid (_cert.SignatureAlgorithm);
- return signature_algorithm;
- }
+ get { return Impl.SignatureAlgorithm; }
}
public X500DistinguishedName SubjectName {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- if (subject_name == null)
- subject_name = new X500DistinguishedName (_cert.GetSubjectName ().GetBytes ());
- return subject_name;
- }
+ get { return Impl.SubjectName; }
}
public string Thumbprint {
- get { return base.GetCertHashString (); }
+ get { return GetCertHashString (); }
}
public int Version {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _cert.Version;
- }
+ get { return Impl.Version; }
}
// methods
[MonoTODO ("always return String.Empty for UpnName, DnsFromAlternativeName and UrlName")]
public string GetNameInfo (X509NameType nameType, bool forIssuer)
{
- switch (nameType) {
- case X509NameType.SimpleName:
- if (_cert == null)
- throw new CryptographicException (empty_error);
- // return CN= or, if missing, the first part of the DN
- ASN1 sn = forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ();
- ASN1 dn = Find (commonName, sn);
- if (dn != null)
- return GetValueAsString (dn);
- if (sn.Count == 0)
- return String.Empty;
- ASN1 last_entry = sn [sn.Count - 1];
- if (last_entry.Count == 0)
- return String.Empty;
- return GetValueAsString (last_entry [0]);
- case X509NameType.EmailName:
- // return the E= part of the DN (if present)
- ASN1 e = Find (email, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
- if (e != null)
- return GetValueAsString (e);
- return String.Empty;
- case X509NameType.UpnName:
- // FIXME - must find/create test case
- return String.Empty;
- case X509NameType.DnsName:
- // return the CN= part of the DN (if present)
- ASN1 cn = Find (commonName, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
- if (cn != null)
- return GetValueAsString (cn);
- return String.Empty;
- case X509NameType.DnsFromAlternativeName:
- // FIXME - must find/create test case
- return String.Empty;
- case X509NameType.UrlName:
- // FIXME - must find/create test case
- return String.Empty;
- default:
- throw new ArgumentException ("nameType");
- }
- }
-
- static byte[] commonName = { 0x55, 0x04, 0x03 };
- static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
-
- private ASN1 Find (byte[] oid, ASN1 dn)
- {
- if (dn.Count == 0)
- return null;
-
- // process SET
- for (int i = 0; i < dn.Count; i++) {
- ASN1 set = dn [i];
- for (int j = 0; j < set.Count; j++) {
- ASN1 pair = set [j];
- if (pair.Count != 2)
- continue;
-
- ASN1 poid = pair [0];
- if (poid == null)
- continue;
-
- if (poid.CompareValue (oid))
- return pair;
- }
- }
- return null;
- }
-
- private string GetValueAsString (ASN1 pair)
- {
- if (pair.Count != 2)
- return String.Empty;
-
- ASN1 value = pair [1];
- if ((value.Value == null) || (value.Length == 0))
- return String.Empty;
-
- if (value.Tag == 0x1E) {
- // BMPSTRING
- StringBuilder sb = new StringBuilder ();
- for (int j = 1; j < value.Value.Length; j += 2)
- sb.Append ((char)value.Value [j]);
- return sb.ToString ();
- } else {
- return Encoding.UTF8.GetString (value.Value);
- }
- }
-
- private MX.X509Certificate ImportPkcs12 (byte[] rawData, string password)
- {
- MX.PKCS12 pfx = null;
- if (string.IsNullOrEmpty (password)) {
- try {
- // Support both unencrypted PKCS#12..
- pfx = new MX.PKCS12 (rawData, (string)null);
- } catch {
- // ..and PKCS#12 encrypted with an empty password
- pfx = new MX.PKCS12 (rawData, string.Empty);
- }
- } else {
- pfx = new MX.PKCS12 (rawData, password);
- }
-
- if (pfx.Certificates.Count == 0) {
- // no certificate was found
- return null;
- } else if (pfx.Keys.Count == 0) {
- // no key were found - pick the first certificate
- return pfx.Certificates [0];
- } else {
- // find the certificate that match the first key
- MX.X509Certificate cert = null;
- var keypair = (pfx.Keys [0] as AsymmetricAlgorithm);
- string pubkey = keypair.ToXmlString (false);
- foreach (var c in pfx.Certificates) {
- if (((c.RSA != null) && (pubkey == c.RSA.ToXmlString (false))) ||
- ((c.DSA != null) && (pubkey == c.DSA.ToXmlString (false)))) {
- cert = c;
- break;
- }
- }
- if (cert == null) {
- cert = pfx.Certificates [0]; // no match, pick first certificate without keys
- } else {
- cert.RSA = (keypair as RSA);
- cert.DSA = (keypair as DSA);
- }
- return cert;
- }
+ return Impl.GetNameInfo (nameType, forIssuer);
}
public override void Import (byte[] rawData)
[MonoTODO ("missing KeyStorageFlags support")]
public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
{
- MX.X509Certificate cert = null;
- if (password == null) {
- try {
- cert = new MX.X509Certificate (rawData);
- }
- catch (Exception e) {
- try {
- cert = ImportPkcs12 (rawData, null);
- }
- catch {
- string msg = Locale.GetText ("Unable to decode certificate.");
- // inner exception is the original (not second) exception
- throw new CryptographicException (msg, e);
- }
- }
- } else {
- // try PKCS#12
- try {
- cert = ImportPkcs12 (rawData, password);
- }
- catch {
- // it's possible to supply a (unrequired/unusued) password
- // fix bug #79028
- cert = new MX.X509Certificate (rawData);
- }
- }
- // we do not have to fully re-decode the certificate since X509Certificate does not deal with keys
- if (cert != null) {
- base.Import (cert.RawData, (string) null, keyStorageFlags);
- _cert = cert; // becuase base call will call Reset!
- }
+ var impl = X509Helper2.Import (rawData, password, keyStorageFlags);
+ ImportHandle (impl);
}
[MonoTODO ("SecureString is incomplete")]
[MonoTODO ("X509ContentType.SerializedCert is not supported")]
public override byte[] Export (X509ContentType contentType, string password)
{
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- switch (contentType) {
- case X509ContentType.Cert:
- return _cert.RawData;
- case X509ContentType.Pfx: // this includes Pkcs12
- return ExportPkcs12 (password);
- case X509ContentType.SerializedCert:
- // TODO
- throw new NotSupportedException ();
- default:
- string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
- throw new CryptographicException (msg);
- }
- }
-
- byte[] ExportPkcs12 (string password)
- {
- var pfx = new MX.PKCS12 ();
- try {
- if (password != null)
- pfx.Password = password;
- pfx.AddCertificate (_cert);
- var privateKey = PrivateKey;
- if (privateKey != null)
- pfx.AddPkcs8ShroudedKeyBag (privateKey);
- return pfx.GetBytes ();
- } finally {
- pfx.Password = null;
- }
+ return Impl.Export (contentType, password);
}
public override void Reset ()
{
- _cert = null;
- _archived = false;
- _extensions = null;
- _name = String.Empty;
- _serial = null;
- _publicKey = null;
- issuer_name = null;
- subject_name = null;
- signature_algorithm = null;
+ friendlyName = string.Empty;
base.Reset ();
}
public override string ToString ()
{
- if (_cert == null)
+ if (!IsValid)
return "System.Security.Cryptography.X509Certificates.X509Certificate2";
-
return base.ToString (true);
}
public override string ToString (bool verbose)
{
- if (_cert == null)
+ if (!IsValid)
return "System.Security.Cryptography.X509Certificates.X509Certificate2";
// the non-verbose X509Certificate2 == verbose X509Certificate
[MonoTODO ("by default this depends on the incomplete X509Chain")]
public bool Verify ()
{
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- X509Chain chain = X509Chain.Create ();
- if (!chain.Build (this))
- return false;
- // TODO - check chain and other stuff ???
- return true;
+ return Impl.Verify (this);
}
// static methods
// internal stuff because X509Certificate2 isn't complete enough
// (maybe X509Certificate3 will be better?)
+ [Obsolete ("KILL")]
internal MX.X509Certificate MonoCertificate {
- get { return _cert; }
+ get {
+ var monoImpl = Impl as X509Certificate2ImplMono;
+ if (monoImpl == null)
+ throw new NotSupportedException ();
+ return monoImpl.MonoCertificate;
+ }
}
#else
--- /dev/null
+//
+// X509Certificate2Impl.cs
+//
+// Authors:
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
+//
+// 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.
+//
+namespace System.Security.Cryptography.X509Certificates
+{
+ internal abstract class X509Certificate2Impl : X509CertificateImpl
+ {
+#if SECURITY_DEP
+
+ public abstract bool Archived {
+ get; set;
+ }
+
+ public abstract X509ExtensionCollection Extensions {
+ get;
+ }
+
+ public abstract bool HasPrivateKey {
+ get;
+ }
+
+ public abstract X500DistinguishedName IssuerName {
+ get;
+ }
+
+ public abstract AsymmetricAlgorithm PrivateKey {
+ get; set;
+ }
+
+ public abstract PublicKey PublicKey {
+ get;
+ }
+
+ public abstract Oid SignatureAlgorithm {
+ get;
+ }
+
+ public abstract X500DistinguishedName SubjectName {
+ get;
+ }
+
+ public abstract int Version {
+ get;
+ }
+
+ public abstract string GetNameInfo (X509NameType nameType, bool forIssuer);
+
+ public abstract void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags);
+
+ public abstract byte[] Export (X509ContentType contentType, string password);
+
+ public abstract bool Verify (X509Certificate2 thisCertificate);
+
+ public abstract void Reset ();
+
+#endif
+ }
+}
--- /dev/null
+//
+// X509Certificate2ImplMono
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
+// Copyright (C) 2015-2016 Xamarin, Inc. (http://www.xamarin.com)
+//
+// 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.
+//
+
+#if SECURITY_DEP
+
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+using MonoSecurity::Mono.Security;
+using MonoSecurity::Mono.Security.Cryptography;
+using MX = MonoSecurity::Mono.Security.X509;
+#else
+using Mono.Security;
+using Mono.Security.Cryptography;
+using MX = Mono.Security.X509;
+#endif
+
+using System.IO;
+using System.Text;
+using System.Collections;
+
+namespace System.Security.Cryptography.X509Certificates
+{
+ internal class X509Certificate2ImplMono : X509Certificate2Impl
+ {
+ bool _archived;
+ X509ExtensionCollection _extensions;
+ string _serial;
+ PublicKey _publicKey;
+ X500DistinguishedName issuer_name;
+ X500DistinguishedName subject_name;
+ Oid signature_algorithm;
+
+ MX.X509Certificate _cert;
+
+ static string empty_error = Locale.GetText ("Certificate instance is empty.");
+
+ public override bool IsValid {
+ get {
+ return _cert != null;
+ }
+ }
+
+ public override IntPtr Handle {
+ get { return IntPtr.Zero; }
+ }
+
+ internal X509Certificate2ImplMono (MX.X509Certificate cert)
+ {
+ this._cert = cert;
+ }
+
+ public override X509CertificateImpl Clone ()
+ {
+ ThrowIfContextInvalid ();
+ return new X509Certificate2ImplMono (_cert);
+ }
+
+ #region Implemented X509CertificateImpl members
+
+ public override string GetIssuerName (bool legacyV1Mode)
+ {
+ ThrowIfContextInvalid ();
+ if (legacyV1Mode)
+ return _cert.IssuerName;
+ else
+ return MX.X501.ToString (_cert.GetIssuerName (), true, ", ", true);
+ }
+
+ public override string GetSubjectName (bool legacyV1Mode)
+ {
+ ThrowIfContextInvalid ();
+ if (legacyV1Mode)
+ return _cert.SubjectName;
+ else
+ return MX.X501.ToString (_cert.GetSubjectName (), true, ", ", true);
+ }
+
+ public override byte[] GetRawCertData ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.RawData;
+ }
+
+ protected override byte[] GetCertHash (bool lazy)
+ {
+ ThrowIfContextInvalid ();
+ SHA1 sha = SHA1.Create ();
+ return sha.ComputeHash (_cert.RawData);
+ }
+
+ public override DateTime GetValidFrom ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.ValidFrom;
+ }
+
+ public override DateTime GetValidUntil ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.ValidUntil;
+ }
+
+ public override bool Equals (X509CertificateImpl other, out bool result)
+ {
+ // Use default implementation
+ result = false;
+ return false;
+ }
+
+ public override string GetKeyAlgorithm ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.KeyAlgorithm;
+ }
+
+ public override byte[] GetKeyAlgorithmParameters ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.KeyAlgorithmParameters;
+ }
+
+ public override byte[] GetPublicKey ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.PublicKey;
+ }
+
+ public override byte[] GetSerialNumber ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.SerialNumber;
+ }
+
+ public override byte[] Export (X509ContentType contentType, byte[] password)
+ {
+ ThrowIfContextInvalid ();
+
+ switch (contentType) {
+ case X509ContentType.Cert:
+ return GetRawCertData ();
+ case X509ContentType.Pfx: // this includes Pkcs12
+ // TODO
+ throw new NotSupportedException ();
+ case X509ContentType.SerializedCert:
+ // TODO
+ throw new NotSupportedException ();
+ default:
+ string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
+ throw new CryptographicException (msg);
+ }
+ }
+
+ #endregion
+
+ // constructors
+
+ public X509Certificate2ImplMono ()
+ {
+ _cert = null;
+ }
+
+ // properties
+
+ public override bool Archived {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ return _archived;
+ }
+ set {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ _archived = value;
+ }
+ }
+
+ public override X509ExtensionCollection Extensions {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ if (_extensions == null)
+ _extensions = new X509ExtensionCollection (_cert);
+ return _extensions;
+ }
+ }
+
+ // FIXME - Could be more efficient
+ public override bool HasPrivateKey {
+ get { return PrivateKey != null; }
+ }
+
+ public override X500DistinguishedName IssuerName {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ if (issuer_name == null)
+ issuer_name = new X500DistinguishedName (_cert.GetIssuerName ().GetBytes ());
+ return issuer_name;
+ }
+ }
+
+ public override AsymmetricAlgorithm PrivateKey {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ try {
+ if (_cert.RSA != null) {
+ RSACryptoServiceProvider rcsp = _cert.RSA as RSACryptoServiceProvider;
+ if (rcsp != null)
+ return rcsp.PublicOnly ? null : rcsp;
+
+ RSAManaged rsam = _cert.RSA as RSAManaged;
+ if (rsam != null)
+ return rsam.PublicOnly ? null : rsam;
+
+ _cert.RSA.ExportParameters (true);
+ return _cert.RSA;
+ } else if (_cert.DSA != null) {
+ DSACryptoServiceProvider dcsp = _cert.DSA as DSACryptoServiceProvider;
+ if (dcsp != null)
+ return dcsp.PublicOnly ? null : dcsp;
+
+ _cert.DSA.ExportParameters (true);
+ return _cert.DSA;
+ }
+ }
+ catch {
+ }
+ return null;
+ }
+ set {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ // allow NULL so we can "forget" the key associated to the certificate
+ // e.g. in case we want to export it in another format (see bug #396620)
+ if (value == null) {
+ _cert.RSA = null;
+ _cert.DSA = null;
+ } else if (value is RSA)
+ _cert.RSA = (RSA) value;
+ else if (value is DSA)
+ _cert.DSA = (DSA) value;
+ else
+ throw new NotSupportedException ();
+ }
+ }
+
+ public override PublicKey PublicKey {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ if (_publicKey == null) {
+ try {
+ _publicKey = new PublicKey (_cert);
+ }
+ catch (Exception e) {
+ string msg = Locale.GetText ("Unable to decode public key.");
+ throw new CryptographicException (msg, e);
+ }
+ }
+ return _publicKey;
+ }
+ }
+
+ public override Oid SignatureAlgorithm {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ if (signature_algorithm == null)
+ signature_algorithm = new Oid (_cert.SignatureAlgorithm);
+ return signature_algorithm;
+ }
+ }
+
+ public override X500DistinguishedName SubjectName {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ if (subject_name == null)
+ subject_name = new X500DistinguishedName (_cert.GetSubjectName ().GetBytes ());
+ return subject_name;
+ }
+ }
+
+ public override int Version {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ return _cert.Version;
+ }
+ }
+
+ // methods
+
+ [MonoTODO ("always return String.Empty for UpnName, DnsFromAlternativeName and UrlName")]
+ public override string GetNameInfo (X509NameType nameType, bool forIssuer)
+ {
+ switch (nameType) {
+ case X509NameType.SimpleName:
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ // return CN= or, if missing, the first part of the DN
+ ASN1 sn = forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ();
+ ASN1 dn = Find (commonName, sn);
+ if (dn != null)
+ return GetValueAsString (dn);
+ if (sn.Count == 0)
+ return String.Empty;
+ ASN1 last_entry = sn [sn.Count - 1];
+ if (last_entry.Count == 0)
+ return String.Empty;
+ return GetValueAsString (last_entry [0]);
+ case X509NameType.EmailName:
+ // return the E= part of the DN (if present)
+ ASN1 e = Find (email, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
+ if (e != null)
+ return GetValueAsString (e);
+ return String.Empty;
+ case X509NameType.UpnName:
+ // FIXME - must find/create test case
+ return String.Empty;
+ case X509NameType.DnsName:
+ // return the CN= part of the DN (if present)
+ ASN1 cn = Find (commonName, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
+ if (cn != null)
+ return GetValueAsString (cn);
+ return String.Empty;
+ case X509NameType.DnsFromAlternativeName:
+ // FIXME - must find/create test case
+ return String.Empty;
+ case X509NameType.UrlName:
+ // FIXME - must find/create test case
+ return String.Empty;
+ default:
+ throw new ArgumentException ("nameType");
+ }
+ }
+
+ static byte[] commonName = { 0x55, 0x04, 0x03 };
+ static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
+
+ private ASN1 Find (byte[] oid, ASN1 dn)
+ {
+ if (dn.Count == 0)
+ return null;
+
+ // process SET
+ for (int i = 0; i < dn.Count; i++) {
+ ASN1 set = dn [i];
+ for (int j = 0; j < set.Count; j++) {
+ ASN1 pair = set [j];
+ if (pair.Count != 2)
+ continue;
+
+ ASN1 poid = pair [0];
+ if (poid == null)
+ continue;
+
+ if (poid.CompareValue (oid))
+ return pair;
+ }
+ }
+ return null;
+ }
+
+ private string GetValueAsString (ASN1 pair)
+ {
+ if (pair.Count != 2)
+ return String.Empty;
+
+ ASN1 value = pair [1];
+ if ((value.Value == null) || (value.Length == 0))
+ return String.Empty;
+
+ if (value.Tag == 0x1E) {
+ // BMPSTRING
+ StringBuilder sb = new StringBuilder ();
+ for (int j = 1; j < value.Value.Length; j += 2)
+ sb.Append ((char)value.Value [j]);
+ return sb.ToString ();
+ } else {
+ return Encoding.UTF8.GetString (value.Value);
+ }
+ }
+
+ private MX.X509Certificate ImportPkcs12 (byte[] rawData, string password)
+ {
+ MX.PKCS12 pfx = null;
+ if (string.IsNullOrEmpty (password)) {
+ try {
+ // Support both unencrypted PKCS#12..
+ pfx = new MX.PKCS12 (rawData, (string)null);
+ } catch {
+ // ..and PKCS#12 encrypted with an empty password
+ pfx = new MX.PKCS12 (rawData, string.Empty);
+ }
+ } else {
+ pfx = new MX.PKCS12 (rawData, password);
+ }
+
+ if (pfx.Certificates.Count == 0) {
+ // no certificate was found
+ return null;
+ } else if (pfx.Keys.Count == 0) {
+ // no key were found - pick the first certificate
+ return pfx.Certificates [0];
+ } else {
+ // find the certificate that match the first key
+ MX.X509Certificate cert = null;
+ var keypair = (pfx.Keys [0] as AsymmetricAlgorithm);
+ string pubkey = keypair.ToXmlString (false);
+ foreach (var c in pfx.Certificates) {
+ if (((c.RSA != null) && (pubkey == c.RSA.ToXmlString (false))) ||
+ ((c.DSA != null) && (pubkey == c.DSA.ToXmlString (false)))) {
+ cert = c;
+ break;
+ }
+ }
+ if (cert == null) {
+ cert = pfx.Certificates [0]; // no match, pick first certificate without keys
+ } else {
+ cert.RSA = (keypair as RSA);
+ cert.DSA = (keypair as DSA);
+ }
+ return cert;
+ }
+ }
+
+ [MonoTODO ("missing KeyStorageFlags support")]
+ public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
+ {
+ MX.X509Certificate cert = null;
+ if (password == null) {
+ try {
+ cert = new MX.X509Certificate (rawData);
+ }
+ catch (Exception e) {
+ try {
+ cert = ImportPkcs12 (rawData, null);
+ }
+ catch {
+ string msg = Locale.GetText ("Unable to decode certificate.");
+ // inner exception is the original (not second) exception
+ throw new CryptographicException (msg, e);
+ }
+ }
+ } else {
+ // try PKCS#12
+ try {
+ cert = ImportPkcs12 (rawData, password);
+ }
+ catch {
+ // it's possible to supply a (unrequired/unusued) password
+ // fix bug #79028
+ cert = new MX.X509Certificate (rawData);
+ }
+ }
+ _cert = cert;
+ }
+
+ [MonoTODO ("X509ContentType.SerializedCert is not supported")]
+ public override byte[] Export (X509ContentType contentType, string password)
+ {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ switch (contentType) {
+ case X509ContentType.Cert:
+ return _cert.RawData;
+ case X509ContentType.Pfx: // this includes Pkcs12
+ return ExportPkcs12 (password);
+ case X509ContentType.SerializedCert:
+ // TODO
+ throw new NotSupportedException ();
+ default:
+ string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
+ throw new CryptographicException (msg);
+ }
+ }
+
+ byte[] ExportPkcs12 (string password)
+ {
+ var pfx = new MX.PKCS12 ();
+ try {
+ var attrs = new Hashtable ();
+ var localKeyId = new ArrayList ();
+ localKeyId.Add (new byte[] { 1, 0, 0, 0 });
+ attrs.Add (MX.PKCS9.localKeyId, localKeyId);
+
+ if (password != null)
+ pfx.Password = password;
+ pfx.AddCertificate (_cert, attrs);
+ var privateKey = PrivateKey;
+ if (privateKey != null)
+ pfx.AddPkcs8ShroudedKeyBag (privateKey, attrs);
+ return pfx.GetBytes ();
+ } finally {
+ pfx.Password = null;
+ }
+ }
+
+ public override void Reset ()
+ {
+ _cert = null;
+ _archived = false;
+ _extensions = null;
+ _serial = null;
+ _publicKey = null;
+ issuer_name = null;
+ subject_name = null;
+ signature_algorithm = null;
+ }
+
+ public override string ToString ()
+ {
+ if (_cert == null)
+ return "System.Security.Cryptography.X509Certificates.X509Certificate2";
+
+ return ToString (true);
+ }
+
+ public override string ToString (bool verbose)
+ {
+ if (_cert == null)
+ return "System.Security.Cryptography.X509Certificates.X509Certificate2";
+
+ string nl = Environment.NewLine;
+ StringBuilder sb = new StringBuilder ();
+
+ // the non-verbose X509Certificate2 == verbose X509Certificate
+ if (!verbose) {
+ sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
+ sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
+ sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
+ sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
+ sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
+ sb.Append (nl);
+ return sb.ToString ();
+ }
+
+ sb.AppendFormat ("[Version]{0} V{1}{0}{0}", nl, Version);
+ sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
+ sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
+ sb.AppendFormat ("[Serial Number]{0} {1}{0}{0}", nl, GetSerialNumber ());
+ sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
+ sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
+ sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
+ sb.AppendFormat ("[Signature Algorithm]{0} {1}({2}){0}{0}", nl, SignatureAlgorithm.FriendlyName,
+ SignatureAlgorithm.Value);
+
+ AsymmetricAlgorithm key = PublicKey.Key;
+ sb.AppendFormat ("[Public Key]{0} Algorithm: ", nl);
+ if (key is RSA)
+ sb.Append ("RSA");
+ else if (key is DSA)
+ sb.Append ("DSA");
+ else
+ sb.Append (key.ToString ());
+ sb.AppendFormat ("{0} Length: {1}{0} Key Blob: ", nl, key.KeySize);
+ AppendBuffer (sb, PublicKey.EncodedKeyValue.RawData);
+ sb.AppendFormat ("{0} Parameters: ", nl);
+ AppendBuffer (sb, PublicKey.EncodedParameters.RawData);
+ sb.Append (nl);
+
+ return sb.ToString ();
+ }
+
+ private static void AppendBuffer (StringBuilder sb, byte[] buffer)
+ {
+ if (buffer == null)
+ return;
+ for (int i=0; i < buffer.Length; i++) {
+ sb.Append (buffer [i].ToString ("x2"));
+ if (i < buffer.Length - 1)
+ sb.Append (" ");
+ }
+ }
+
+ [MonoTODO ("by default this depends on the incomplete X509Chain")]
+ public override bool Verify (X509Certificate2 thisCertificate)
+ {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ X509Chain chain = X509Chain.Create ();
+ if (!chain.Build (thisCertificate))
+ return false;
+ // TODO - check chain and other stuff ???
+ return true;
+ }
+
+ // static methods
+
+ private static byte[] signedData = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 };
+
+ [MonoTODO ("Detection limited to Cert, Pfx, Pkcs12, Pkcs7 and Unknown")]
+ public static X509ContentType GetCertContentType (byte[] rawData)
+ {
+ if ((rawData == null) || (rawData.Length == 0))
+ throw new ArgumentException ("rawData");
+
+ X509ContentType type = X509ContentType.Unknown;
+ try {
+ ASN1 data = new ASN1 (rawData);
+ if (data.Tag != 0x30) {
+ string msg = Locale.GetText ("Unable to decode certificate.");
+ throw new CryptographicException (msg);
+ }
+
+ if (data.Count == 0)
+ return type;
+
+ if (data.Count == 3) {
+ switch (data [0].Tag) {
+ case 0x30:
+ // SEQUENCE / SEQUENCE / BITSTRING
+ if ((data [1].Tag == 0x30) && (data [2].Tag == 0x03))
+ type = X509ContentType.Cert;
+ break;
+ case 0x02:
+ // INTEGER / SEQUENCE / SEQUENCE
+ if ((data [1].Tag == 0x30) && (data [2].Tag == 0x30))
+ type = X509ContentType.Pkcs12;
+ // note: Pfx == Pkcs12
+ break;
+ }
+ }
+ // check for PKCS#7 (count unknown but greater than 0)
+ // SEQUENCE / OID (signedData)
+ if ((data [0].Tag == 0x06) && data [0].CompareValue (signedData))
+ type = X509ContentType.Pkcs7;
+ }
+ catch (Exception e) {
+ string msg = Locale.GetText ("Unable to decode certificate.");
+ throw new CryptographicException (msg, e);
+ }
+
+ return type;
+ }
+
+ [MonoTODO ("Detection limited to Cert, Pfx, Pkcs12 and Unknown")]
+ public static X509ContentType GetCertContentType (string fileName)
+ {
+ if (fileName == null)
+ throw new ArgumentNullException ("fileName");
+ if (fileName.Length == 0)
+ throw new ArgumentException ("fileName");
+
+ byte[] data = File.ReadAllBytes (fileName);
+ return GetCertContentType (data);
+ }
+
+ // internal stuff because X509Certificate2 isn't complete enough
+ // (maybe X509Certificate3 will be better?)
+
+ internal MX.X509Certificate MonoCertificate {
+ get { return _cert; }
+ }
+ }
+}
+
+#endif
namespace System.Security.Cryptography.X509Certificates {
- public class X509Chain {
+ public class X509Chain : IDisposable {
- private StoreLocation location;
- private X509ChainElementCollection elements;
- private X509ChainPolicy policy;
- private X509ChainStatus[] status;
+ X509ChainImpl impl;
static X509ChainStatus[] Empty = new X509ChainStatus [0];
- // RFC3280 variables
- private int max_path_length;
- private X500DistinguishedName working_issuer_name;
-// private string working_public_key_algorithm;
- private AsymmetricAlgorithm working_public_key;
+ internal X509ChainImpl Impl {
+ get {
+ X509Helper2.ThrowIfContextInvalid (impl);
+ return impl;
+ }
+ }
- // other flags
- private X509ChainElement bce_restriction;
+ internal bool IsValid {
+ get { return X509Helper2.IsValid (impl); }
+ }
+
+ internal void ThrowIfContextInvalid ()
+ {
+ X509Helper2.ThrowIfContextInvalid (impl);
+ }
// constructors
public X509Chain (bool useMachineContext)
{
- location = useMachineContext ? StoreLocation.LocalMachine : StoreLocation.CurrentUser;
- elements = new X509ChainElementCollection ();
- policy = new X509ChainPolicy ();
+ impl = X509Helper2.CreateChainImpl (useMachineContext);
+ }
+
+ internal X509Chain (X509ChainImpl impl)
+ {
+ X509Helper2.ThrowIfContextInvalid (impl);
+ this.impl = impl;
}
[MonoTODO ("Mono's X509Chain is fully managed. All handles are invalid.")]
[MonoTODO ("Mono's X509Chain is fully managed. Always returns IntPtr.Zero.")]
public IntPtr ChainContext {
- get { return IntPtr.Zero; }
+ get {
+ if (impl != null && impl.IsValid)
+ return impl.Handle;
+ return IntPtr.Zero;
+ }
}
public X509ChainElementCollection ChainElements {
- get { return elements; }
+ get { return Impl.ChainElements; }
}
public X509ChainPolicy ChainPolicy {
- get { return policy; }
- set { policy = value; }
+ get { return Impl.ChainPolicy; }
+ set { Impl.ChainPolicy = value; }
}
public X509ChainStatus[] ChainStatus {
- get {
- if (status == null)
- return Empty;
- return status;
- }
- }
+ get { return Impl.ChainStatus; }
+ }
// methods
[MonoTODO ("Not totally RFC3280 compliant, but neither is MS implementation...")]
public bool Build (X509Certificate2 certificate)
{
- if (certificate == null)
- throw new ArgumentException ("certificate");
-
- Reset ();
- X509ChainStatusFlags flag;
- try {
- flag = BuildChainFrom (certificate);
- ValidateChain (flag);
- }
- catch (CryptographicException ce) {
- throw new ArgumentException ("certificate", ce);
- }
-
- X509ChainStatusFlags total = X509ChainStatusFlags.NoError;
- ArrayList list = new ArrayList ();
- // build "global" ChainStatus from the ChainStatus of every ChainElements
- foreach (X509ChainElement ce in elements) {
- foreach (X509ChainStatus cs in ce.ChainElementStatus) {
- // we MUST avoid duplicates in the "global" list
- if ((total & cs.Status) != cs.Status) {
- list.Add (cs);
- total |= cs.Status;
- }
- }
- }
- // and if required add some
- if (flag != X509ChainStatusFlags.NoError) {
- list.Insert (0, new X509ChainStatus (flag));
- }
- status = (X509ChainStatus[]) list.ToArray (typeof (X509ChainStatus));
-
- // (fast path) this ignore everything we have checked
- if ((status.Length == 0) || (ChainPolicy.VerificationFlags == X509VerificationFlags.AllFlags))
- return true;
-
- bool result = true;
- // now check if exclude some verification for the "end result" (boolean)
- foreach (X509ChainStatus cs in status) {
- switch (cs.Status) {
- case X509ChainStatusFlags.UntrustedRoot:
- case X509ChainStatusFlags.PartialChain:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.AllowUnknownCertificateAuthority) != 0);
- break;
- case X509ChainStatusFlags.NotTimeValid:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeValid) != 0);
- break;
- // FIXME - from here we needs new test cases for all cases
- case X509ChainStatusFlags.NotTimeNested:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeNested) != 0);
- break;
- case X509ChainStatusFlags.InvalidBasicConstraints:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidBasicConstraints) != 0);
- break;
- case X509ChainStatusFlags.InvalidPolicyConstraints:
- case X509ChainStatusFlags.NoIssuanceChainPolicy:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidPolicy) != 0);
- break;
- case X509ChainStatusFlags.InvalidNameConstraints:
- case X509ChainStatusFlags.HasNotSupportedNameConstraint:
- case X509ChainStatusFlags.HasNotPermittedNameConstraint:
- case X509ChainStatusFlags.HasExcludedNameConstraint:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidName) != 0);
- break;
- case X509ChainStatusFlags.InvalidExtension:
- // not sure ?!?
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
- break;
- //
- // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreRootRevocationUnknown) != 0)
- // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreEndRevocationUnknown) != 0)
- case X509ChainStatusFlags.CtlNotTimeValid:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlNotTimeValid) != 0);
- break;
- case X509ChainStatusFlags.CtlNotSignatureValid:
- // ?
- break;
- // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlSignerRevocationUnknown) != 0);
- case X509ChainStatusFlags.CtlNotValidForUsage:
- // FIXME - does IgnoreWrongUsage apply to CTL (it doesn't have Ctl in it's name like the others)
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
- break;
- default:
- result = false;
- break;
- }
- // once we have one failure there's no need to check further
- if (!result)
- return false;
- }
-
- // every "problem" was excluded
- return true;
+ return Impl.Build (certificate);
}
public void Reset ()
{
- // note: this call doesn't Reset the X509ChainPolicy
- if ((status != null) && (status.Length != 0))
- status = null;
- if (elements.Count > 0)
- elements.Clear ();
- if (user_root_store != null) {
- user_root_store.Close ();
- user_root_store = null;
- }
- if (root_store != null) {
- root_store.Close ();
- root_store = null;
- }
- if (user_ca_store != null) {
- user_ca_store.Close ();
- user_ca_store = null;
- }
- if (ca_store != null) {
- ca_store.Close ();
- ca_store = null;
- }
- roots = null;
- cas = null;
- collection = null;
- bce_restriction = null;
- working_public_key = null;
+ Impl.Reset ();
}
// static methods
#endif
}
- // private stuff
-
- private X509Certificate2Collection roots;
- private X509Certificate2Collection cas;
- private X509Store root_store;
- private X509Store ca_store;
- private X509Store user_root_store;
- private X509Store user_ca_store;
-
- private X509Certificate2Collection Roots {
- get {
- if (roots == null) {
- X509Certificate2Collection c = new X509Certificate2Collection ();
- X509Store store = LMRootStore;
- if (location == StoreLocation.CurrentUser)
- c.AddRange (UserRootStore.Certificates);
- c.AddRange (store.Certificates);
- roots = c;
- }
- return roots;
- }
- }
-
- private X509Certificate2Collection CertificateAuthorities {
- get {
- if (cas == null) {
- X509Certificate2Collection c = new X509Certificate2Collection ();
- X509Store store = LMCAStore;
- if (location == StoreLocation.CurrentUser)
- c.AddRange (UserCAStore.Certificates);
- c.AddRange (store.Certificates);
- cas = c;
- }
- return cas;
- }
- }
-
- private X509Store LMRootStore {
- get {
- if (root_store == null) {
- root_store = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
- try {
- root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
- } catch {
- }
- }
- return root_store;
- }
- }
-
- private X509Store UserRootStore {
- get {
- if (user_root_store == null) {
- user_root_store = new X509Store (StoreName.Root, StoreLocation.CurrentUser);
- try {
- user_root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
- } catch {
- }
- }
- return user_root_store;
- }
- }
-
- private X509Store LMCAStore {
- get {
- if (ca_store == null) {
- ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.LocalMachine);
- try {
- ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
- } catch {
- }
- }
- return ca_store;
- }
- }
-
- private X509Store UserCAStore {
- get {
- if (user_ca_store == null) {
- user_ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.CurrentUser);
- try {
- user_ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
- } catch {
- }
- }
- return user_ca_store;
- }
- }
- // *** certificate chain/path building stuff ***
-
- private X509Certificate2Collection collection;
-
- // we search local user (default) or machine certificate store
- // and in the extra certificate supplied in ChainPolicy.ExtraStore
- private X509Certificate2Collection CertificateCollection {
- get {
- if (collection == null) {
- collection = new X509Certificate2Collection (ChainPolicy.ExtraStore);
- collection.AddRange (Roots);
- collection.AddRange (CertificateAuthorities);
- }
- return collection;
- }
- }
-
- // This is a non-recursive chain/path building algorithm.
- //
- // At this stage we only checks for PartialChain, Cyclic and UntrustedRoot errors are they
- // affect the path building (other errors are verification errors).
- //
- // Note that the order match the one we need to match MS and not the one defined in RFC3280,
- // we also include the trusted root certificate (trust anchor in RFC3280) in the list.
- // (this isn't an issue, just keep that in mind if you look at the source and the RFC)
- private X509ChainStatusFlags BuildChainFrom (X509Certificate2 certificate)
- {
- elements.Add (certificate);
-
- while (!IsChainComplete (certificate)) {
- certificate = FindParent (certificate);
-
- if (certificate == null)
- return X509ChainStatusFlags.PartialChain;
-
- if (elements.Contains (certificate))
- return X509ChainStatusFlags.Cyclic;
-
- elements.Add (certificate);
- }
-
- // roots may be supplied (e.g. in the ExtraStore) so we need to confirm their
- // trustiness (what a cute word) in the trusted root collection
- if (!Roots.Contains (certificate))
- elements [elements.Count - 1].StatusFlags |= X509ChainStatusFlags.UntrustedRoot;
-
- return X509ChainStatusFlags.NoError;
- }
-
-
- private X509Certificate2 SelectBestFromCollection (X509Certificate2 child, X509Certificate2Collection c)
- {
- switch (c.Count) {
- case 0:
- return null;
- case 1:
- return c [0];
- default:
- // multiple candidate, keep only the ones that are still valid
- X509Certificate2Collection time_valid = c.Find (X509FindType.FindByTimeValid, ChainPolicy.VerificationTime, false);
- switch (time_valid.Count) {
- case 0:
- // that's too restrictive, let's revert and try another thing...
- time_valid = c;
- break;
- case 1:
- return time_valid [0];
- default:
- break;
- }
-
- // again multiple candidates, let's find the AKI that match the SKI (if we have one)
- string aki = GetAuthorityKeyIdentifier (child);
- if (String.IsNullOrEmpty (aki)) {
- return time_valid [0]; // FIXME: out of luck, you get the first one
- }
- foreach (X509Certificate2 parent in time_valid) {
- string ski = GetSubjectKeyIdentifier (parent);
- // if both id are available then they must match
- if (aki == ski)
- return parent;
- }
- return time_valid [0]; // FIXME: out of luck, you get the first one
- }
- }
-
- private X509Certificate2 FindParent (X509Certificate2 certificate)
- {
- X509Certificate2Collection subset = CertificateCollection.Find (X509FindType.FindBySubjectDistinguishedName, certificate.Issuer, false);
- string aki = GetAuthorityKeyIdentifier (certificate);
- if ((aki != null) && (aki.Length > 0)) {
- subset.AddRange (CertificateCollection.Find (X509FindType.FindBySubjectKeyIdentifier, aki, false));
- }
- X509Certificate2 parent = SelectBestFromCollection (certificate, subset);
- // if parent==certificate we're looping but it's not (probably) a bug and not a true cyclic (over n certs)
- return certificate.Equals (parent) ? null : parent;
- }
-
- private bool IsChainComplete (X509Certificate2 certificate)
+ public void Dispose ()
{
- // the chain is complete if we have a self-signed certificate
- if (!IsSelfIssued (certificate))
- return false;
-
- // we're very limited to what we can do without certificate extensions
- if (certificate.Version < 3)
- return true;
-
- // check that Authority Key Identifier == Subject Key Identifier
- // e.g. it will be different if a self-signed certificate is part (not the end) of the chain
- string ski = GetSubjectKeyIdentifier (certificate);
- if (String.IsNullOrEmpty (ski))
- return true;
- string aki = GetAuthorityKeyIdentifier (certificate);
- if (String.IsNullOrEmpty (aki))
- return true;
- // if both id are available then they must match
- return (aki == ski);
+ Dispose (true);
+ GC.SuppressFinalize (this);
}
- // check for "self-issued" certificate - without verifying the signature
- // note that self-issued doesn't always mean it's a root certificate!
- private bool IsSelfIssued (X509Certificate2 certificate)
+ protected virtual void Dispose (bool disposing)
{
- return (certificate.Issuer == certificate.Subject);
- }
-
-
- // *** certificate chain/path validation stuff ***
-
- // Currently a subset of RFC3280 (hopefully a full implementation someday)
- private void ValidateChain (X509ChainStatusFlags flag)
- {
- // 'n' should be the root certificate...
- int n = elements.Count - 1;
- X509Certificate2 certificate = elements [n].Certificate;
-
- // ... and, if so, must be treated outside the chain...
- if (((flag & X509ChainStatusFlags.PartialChain) == 0)) {
- Process (n);
- // deal with the case where the chain == the root certificate
- // (which isn't for RFC3280) part of the chain
- if (n == 0) {
- elements [0].UncompressFlags ();
- return;
- }
- // skip the root certificate when processing the chain (in 6.1.3)
- n--;
- }
- // ... unless the chain is a partial one (then we start with that one)
-
- // 6.1.1 - Inputs
- // 6.1.1.a - a prospective certificate path of length n (i.e. elements)
- // 6.1.1.b - the current date/time (i.e. ChainPolicy.VerificationTime)
- // 6.1.1.c - user-initial-policy-set (i.e. ChainPolicy.CertificatePolicy)
- // 6.1.1.d - the trust anchor information (i.e. certificate, unless it's a partial chain)
- // 6.1.1.e - initial-policy-mapping-inhibit (NOT SUPPORTED BY THE API)
- // 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY THE API)
- // 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED BY THE API)
-
- // 6.1.2 - Initialization (incomplete)
- // 6.1.2.a-f - policy stuff, some TODO, some not supported
- // 6.1.2.g - working public key algorithm
-// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
- // 6.1.2.h-i - our key contains both the "working public key" and "working public key parameters" data
- working_public_key = certificate.PublicKey.Key;
- // 6.1.2.j - working issuer name
- working_issuer_name = certificate.IssuerName;
- // 6.1.2.k - this integer is initialized to n, is decremented for each non-self-issued, certificate and
- // may be reduced to the value in the path length constraint field
- max_path_length = n;
-
- // 6.1.3 - Basic Certificate Processing
- // note: loop looks reversed (the list is) but we process this part just like RFC3280 does
- for (int i = n; i > 0; i--) {
- Process (i);
- // 6.1.4 - preparation for certificate i+1 (for not with i+1, or i-1 in our loop)
- PrepareForNextCertificate (i);
+ if (impl != null) {
+ impl.Dispose ();
+ impl = null;
}
- Process (0);
-
- // 6.1.3.a.3 - revocation checks
- CheckRevocationOnChain (flag);
-
- // 6.1.5 - Wrap-up procedure
- WrapUp ();
}
- private void Process (int n)
+ ~X509Chain ()
{
- X509ChainElement element = elements [n];
- X509Certificate2 certificate = element.Certificate;
-
- // pre-step: DSA certificates may inherit the parameters of their CA
- if ((n != elements.Count - 1) && (certificate.MonoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) {
- if (certificate.MonoCertificate.KeyAlgorithmParameters == null) {
- X509Certificate2 parent = elements [n+1].Certificate;
- certificate.MonoCertificate.KeyAlgorithmParameters = parent.MonoCertificate.KeyAlgorithmParameters;
- }
- }
-
- bool root = (working_public_key == null);
- // 6.1.3.a.1 - check signature (with special case to deal with root certificates)
- if (!IsSignedWith (certificate, root ? certificate.PublicKey.Key : working_public_key)) {
- // another special case where only an end-entity is available and can't be verified.
- // In this case we do not report an invalid signature (since this is unknown)
- if (root || (n != elements.Count - 1) || IsSelfIssued (certificate)) {
- element.StatusFlags |= X509ChainStatusFlags.NotSignatureValid;
- }
- }
-
- // 6.1.3.a.2 - check validity period
- if ((ChainPolicy.VerificationTime < certificate.NotBefore) ||
- (ChainPolicy.VerificationTime > certificate.NotAfter)) {
- element.StatusFlags |= X509ChainStatusFlags.NotTimeValid;
- }
- // TODO - for X509ChainStatusFlags.NotTimeNested (needs global structure)
-
- // note: most of them don't apply to the root certificate
- if (root) {
- return;
- }
-
- // 6.1.3.a.3 - revocation check (we're doing at the last stage)
- // note: you revoke a trusted root by removing it from your trusted store (i.e. no CRL can do this job)
-
- // 6.1.3.a.4 - check certificate issuer name
- if (!X500DistinguishedName.AreEqual (certificate.IssuerName, working_issuer_name)) {
- // NOTE: this is not the "right" error flag, but it's the closest one defined
- element.StatusFlags |= X509ChainStatusFlags.InvalidNameConstraints;
- }
-
- if (!IsSelfIssued (certificate) && (n != 0)) {
- // TODO 6.1.3.b - subject name in the permitted_subtrees ...
- // TODO 6.1.3.c - subject name not within excluded_subtrees...
-
- // TODO - check for X509ChainStatusFlags.InvalidNameConstraint
- // TODO - check for X509ChainStatusFlags.HasNotSupportedNameConstraint
- // TODO - check for X509ChainStatusFlags.HasNotPermittedNameConstraint
- // TODO - check for X509ChainStatusFlags.HasExcludedNameConstraint
- }
-
- // TODO 6.1.3.d - check if certificate policies extension is present
- //if (false) {
- // TODO - for X509ChainStatusFlags.InvalidPolicyConstraints
- // using X509ChainPolicy.ApplicationPolicy and X509ChainPolicy.CertificatePolicy
-
- // TODO - check for X509ChainStatusFlags.NoIssuanceChainPolicy
-
- //} else {
- // TODO 6.1.3.e - set valid_policy_tree to NULL
- //}
-
- // TODO 6.1.3.f - verify explict_policy > 0 if valid_policy_tree != NULL
- }
-
- // CTL == Certificate Trust List / NOT SUPPORTED
- // TODO - check for X509ChainStatusFlags.CtlNotTimeValid
- // TODO - check for X509ChainStatusFlags.CtlNotSignatureValid
- // TODO - check for X509ChainStatusFlags.CtlNotValidForUsage
-
- private void PrepareForNextCertificate (int n)
- {
- X509ChainElement element = elements [n];
- X509Certificate2 certificate = element.Certificate;
-
- // TODO 6.1.4.a-b
-
- // 6.1.4.c
- working_issuer_name = certificate.SubjectName;
- // 6.1.4.d-e - our key includes both the public key and it's parameters
- working_public_key = certificate.PublicKey.Key;
- // 6.1.4.f
-// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
-
- // TODO 6.1.4.g-j
-
- // 6.1.4.k - Verify that the certificate is a CA certificate
- X509BasicConstraintsExtension bce = (certificate.Extensions["2.5.29.19"] as X509BasicConstraintsExtension);
- if (bce != null) {
- if (!bce.CertificateAuthority) {
- element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
- }
- } else if (certificate.Version >= 3) {
- // recent (v3+) CA certificates must include BCE
- element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
- }
-
- // 6.1.4.l - if the certificate isn't self-issued...
- if (!IsSelfIssued (certificate)) {
- // ... verify that max_path_length > 0
- if (max_path_length > 0) {
- max_path_length--;
- } else {
- // to match MS the reported status must be against the certificate
- // with the BCE and not where the path is too long. It also means
- // that this condition has to be reported only once
- if (bce_restriction != null) {
- bce_restriction.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
- }
- }
- }
-
- // 6.1.4.m - if pathLengthConstraint is present...
- if ((bce != null) && (bce.HasPathLengthConstraint)) {
- // ... and is less that max_path_length, set max_path_length to it's value
- if (bce.PathLengthConstraint < max_path_length) {
- max_path_length = bce.PathLengthConstraint;
- bce_restriction = element;
- }
- }
-
- // 6.1.4.n - if key usage extension is present...
- X509KeyUsageExtension kue = (certificate.Extensions["2.5.29.15"] as X509KeyUsageExtension);
- if (kue != null) {
- // ... verify keyCertSign is set
- X509KeyUsageFlags success = X509KeyUsageFlags.KeyCertSign;
- if ((kue.KeyUsages & success) != success)
- element.StatusFlags |= X509ChainStatusFlags.NotValidForUsage;
- }
-
- // 6.1.4.o - recognize and process other critical extension present in the certificate
- ProcessCertificateExtensions (element);
- }
-
- private void WrapUp ()
- {
- X509ChainElement element = elements [0];
- X509Certificate2 certificate = element.Certificate;
-
- // 6.1.5.a - TODO if certificate n (our 0) wasn't self issued and explicit_policy != 0
- if (IsSelfIssued (certificate)) {
- // TODO... decrement explicit_policy by 1
- }
-
- // 6.1.5.b - TODO
-
- // 6.1.5.c,d,e - not required by the X509Chain implementation
-
- // 6.1.5.f - recognize and process other critical extension present in the certificate
- ProcessCertificateExtensions (element);
-
- // 6.1.5.g - TODO
-
- // uncompressed the flags into several elements
- for (int i = elements.Count - 1; i >= 0; i--) {
- elements [i].UncompressFlags ();
- }
- }
-
- private void ProcessCertificateExtensions (X509ChainElement element)
- {
- foreach (X509Extension ext in element.Certificate.Extensions) {
- if (ext.Critical) {
- switch (ext.Oid.Value) {
- case "2.5.29.15": // X509KeyUsageExtension
- case "2.5.29.19": // X509BasicConstraintsExtension
- // we processed this extension
- break;
- default:
- // note: Under Windows XP MS implementation seems to ignore
- // certificate with unknown critical extensions.
- element.StatusFlags |= X509ChainStatusFlags.InvalidExtension;
- break;
- }
- }
- }
- }
-
- private bool IsSignedWith (X509Certificate2 signed, AsymmetricAlgorithm pubkey)
- {
- if (pubkey == null)
- return false;
- // Sadly X509Certificate2 doesn't expose the signature nor the tbs (to be signed) structure
- MX.X509Certificate mx = signed.MonoCertificate;
- return (mx.VerifySignature (pubkey));
- }
-
- private string GetSubjectKeyIdentifier (X509Certificate2 certificate)
- {
- X509SubjectKeyIdentifierExtension ski = (certificate.Extensions["2.5.29.14"] as X509SubjectKeyIdentifierExtension);
- return (ski == null) ? String.Empty : ski.SubjectKeyIdentifier;
- }
-
- // System.dll v2 doesn't have a class to deal with the AuthorityKeyIdentifier extension
- static string GetAuthorityKeyIdentifier (X509Certificate2 certificate)
- {
- return GetAuthorityKeyIdentifier (certificate.MonoCertificate.Extensions ["2.5.29.35"]);
- }
-
- // but anyway System.dll v2 doesn't expose CRL in any way so...
- static string GetAuthorityKeyIdentifier (MX.X509Crl crl)
- {
- return GetAuthorityKeyIdentifier (crl.Extensions ["2.5.29.35"]);
- }
-
- static string GetAuthorityKeyIdentifier (MX.X509Extension ext)
- {
- if (ext == null)
- return String.Empty;
- MX.Extensions.AuthorityKeyIdentifierExtension aki = new MX.Extensions.AuthorityKeyIdentifierExtension (ext);
- byte[] id = aki.Identifier;
- if (id == null)
- return String.Empty;
- StringBuilder sb = new StringBuilder ();
- foreach (byte b in id)
- sb.Append (b.ToString ("X02"));
- return sb.ToString ();
- }
-
- // we check the revocation only once we have built the complete chain
- private void CheckRevocationOnChain (X509ChainStatusFlags flag)
- {
- bool partial = ((flag & X509ChainStatusFlags.PartialChain) != 0);
- bool online;
-
- switch (ChainPolicy.RevocationMode) {
- case X509RevocationMode.Online:
- // default
- online = true;
- break;
- case X509RevocationMode.Offline:
- online = false;
- break;
- case X509RevocationMode.NoCheck:
- return;
- default:
- throw new InvalidOperationException (Locale.GetText ("Invalid revocation mode."));
- }
-
- bool unknown = partial;
- // from the root down to the end-entity
- for (int i = elements.Count - 1; i >= 0; i--) {
- bool check = true;
-
- switch (ChainPolicy.RevocationFlag) {
- case X509RevocationFlag.EndCertificateOnly:
- check = (i == 0);
- break;
- case X509RevocationFlag.EntireChain:
- check = true;
- break;
- case X509RevocationFlag.ExcludeRoot:
- // default
- check = (i != (elements.Count - 1));
- // anyway, who's gonna sign that the root is invalid ?
- break;
- }
-
- X509ChainElement element = elements [i];
-
- // we can't assume the revocation status if the certificate is bad (e.g. invalid signature)
- if (!unknown)
- unknown |= ((element.StatusFlags & X509ChainStatusFlags.NotSignatureValid) != 0);
-
- if (unknown) {
- // we can skip the revocation checks as we can't be sure of them anyway
- element.StatusFlags |= X509ChainStatusFlags.RevocationStatusUnknown;
- element.StatusFlags |= X509ChainStatusFlags.OfflineRevocation;
- } else if (check && !partial && !IsSelfIssued (element.Certificate)) {
- // check for revocation (except for the trusted root and self-issued certs)
- element.StatusFlags |= CheckRevocation (element.Certificate, i+1, online);
- // if revoked, then all others following in the chain are unknown...
- unknown |= ((element.StatusFlags & X509ChainStatusFlags.Revoked) != 0);
- }
- }
- }
-
- // This isn't how RFC3280 (section 6.3) deals with CRL, but then we don't (yet) support DP, deltas...
- private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, int ca, bool online)
- {
- X509ChainStatusFlags result = X509ChainStatusFlags.RevocationStatusUnknown;
- X509ChainElement element = elements [ca];
- X509Certificate2 ca_cert = element.Certificate;
-
- // find the CRL from the "right" CA
- while (IsSelfIssued (ca_cert) && (ca < elements.Count - 1)) {
- // try with this self-issued
- result = CheckRevocation (certificate, ca_cert, online);
- if (result != X509ChainStatusFlags.RevocationStatusUnknown)
- break;
- ca++;
- element = elements [ca];
- ca_cert = element.Certificate;
- }
- if (result == X509ChainStatusFlags.RevocationStatusUnknown)
- result = CheckRevocation (certificate, ca_cert, online);
- return result;
- }
-
- private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, X509Certificate2 ca_cert, bool online)
- {
- // change this if/when we support OCSP
- X509KeyUsageExtension kue = (ca_cert.Extensions["2.5.29.15"] as X509KeyUsageExtension);
- if (kue != null) {
- // ... verify CrlSign is set
- X509KeyUsageFlags success = X509KeyUsageFlags.CrlSign;
- if ((kue.KeyUsages & success) != success) {
- // FIXME - we should try to find an alternative CA that has the CrlSign bit
- return X509ChainStatusFlags.RevocationStatusUnknown;
- }
- }
-
- MX.X509Crl crl = FindCrl (ca_cert);
-
- if ((crl == null) && online) {
- // FIXME - download and install new CRL
- // then you get a second chance
- // crl = FindCrl (ca_cert, ref valid, ref out_of_date);
-
- // We need to get the subjectAltName and an URI from there (or use OCSP)
- // X509KeyUsageExtension subjectAltName = (ca_cert.Extensions["2.5.29.17"] as X509KeyUsageExtension);
- }
-
- if (crl != null) {
- // validate the digital signature on the CRL using the CA public key
- // note #1: we can't use X509Crl.VerifySignature(X509Certificate) because it duplicates
- // checks and we loose the "why" of the failure
- // note #2: we do this before other tests as an invalid signature could be a hacked CRL
- // (so anything within can't be trusted)
- if (!crl.VerifySignature (ca_cert.PublicKey.Key)) {
- return X509ChainStatusFlags.RevocationStatusUnknown;
- }
-
- MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry (certificate.MonoCertificate);
- if (entry != null) {
- // We have an entry for this CRL that includes an unknown CRITICAL extension
- // See [X.509 7.3] NOTE 4
- if (!ProcessCrlEntryExtensions (entry))
- return X509ChainStatusFlags.Revoked;
-
- // FIXME - a little more is involved
- if (entry.RevocationDate <= ChainPolicy.VerificationTime)
- return X509ChainStatusFlags.Revoked;
- }
-
- // are we overdue for a CRL update ? if so we can't be sure of any certificate status
- if (crl.NextUpdate < ChainPolicy.VerificationTime)
- return X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation;
-
- // we have a CRL that includes an unknown CRITICAL extension
- // we put this check at the end so we do not "hide" any Revoked flags
- if (!ProcessCrlExtensions (crl)) {
- return X509ChainStatusFlags.RevocationStatusUnknown;
- }
- } else {
- return X509ChainStatusFlags.RevocationStatusUnknown;
- }
-
- return X509ChainStatusFlags.NoError;
- }
-
- static MX.X509Crl CheckCrls (string subject, string ski, MX.X509Store store)
- {
- if (store == null)
- return null;
-
- var crls = store.Crls;
- foreach (MX.X509Crl crl in crls) {
- if (crl.IssuerName == subject && (ski.Length == 0 || ski == GetAuthorityKeyIdentifier (crl)))
- return crl;
- }
- return null; // No CRL found
- }
-
- private MX.X509Crl FindCrl (X509Certificate2 caCertificate)
- {
- string subject = caCertificate.SubjectName.Decode (X500DistinguishedNameFlags.None);
- string ski = GetSubjectKeyIdentifier (caCertificate);
-
- // consider that the LocalMachine directories could not exists... and cannot be created by the user
- MX.X509Crl result = CheckCrls (subject, ski, LMCAStore.Store);
- if (result != null)
- return result;
- if (location == StoreLocation.CurrentUser) {
- result = CheckCrls (subject, ski, UserCAStore.Store);
- if (result != null)
- return result;
- }
-
- // consider that the LocalMachine directories could not exists... and cannot be created by the user
- result = CheckCrls (subject, ski, LMRootStore.Store);
- if (result != null)
- return result;
- if (location == StoreLocation.CurrentUser) {
- result = CheckCrls (subject, ski, UserRootStore.Store);
- if (result != null)
- return result;
- }
- return null;
- }
-
- private bool ProcessCrlExtensions (MX.X509Crl crl)
- {
- foreach (MX.X509Extension ext in crl.Extensions) {
- if (ext.Critical) {
- switch (ext.Oid) {
- case "2.5.29.20": // cRLNumber
- case "2.5.29.35": // authorityKeyIdentifier
- // we processed/know about this extension
- break;
- default:
- return false;
- }
- }
- }
- return true;
- }
-
- private bool ProcessCrlEntryExtensions (MX.X509Crl.X509CrlEntry entry)
- {
- foreach (MX.X509Extension ext in entry.Extensions) {
- if (ext.Critical) {
- switch (ext.Oid) {
- case "2.5.29.21": // cRLReason
- // we processed/know about this extension
- break;
- default:
- return false;
- }
- }
- }
- return true;
+ Dispose (false);
}
}
}
--- /dev/null
+//
+// X509ChainImpl.cs
+//
+// Authors:
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
+//
+// 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.
+//
+#if SECURITY_DEP
+
+namespace System.Security.Cryptography.X509Certificates
+{
+ internal abstract class X509ChainImpl : IDisposable
+ {
+ public abstract bool IsValid {
+ get;
+ }
+
+ public abstract IntPtr Handle {
+ get;
+ }
+
+ protected void ThrowIfContextInvalid ()
+ {
+ if (!IsValid)
+ throw X509Helper2.GetInvalidChainContextException ();
+ }
+
+ public abstract X509ChainElementCollection ChainElements {
+ get;
+ }
+
+ public abstract X509ChainPolicy ChainPolicy {
+ get; set;
+ }
+
+ public abstract X509ChainStatus[] ChainStatus {
+ get;
+ }
+
+ public abstract bool Build (X509Certificate2 certificate);
+
+ public abstract void Reset ();
+
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+
+ protected virtual void Dispose (bool disposing)
+ {
+ }
+
+ ~X509ChainImpl ()
+ {
+ Dispose (false);
+ }
+ }
+}
+
+#endif
--- /dev/null
+//
+// System.Security.Cryptography.X509Certificates.X509ChainImplMono
+//
+// Author:
+// Sebastien Pouliot <sebastien@ximian.com>
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
+// Copyright (C) 2011 Xamarin Inc. (http://www.xamarin.com)
+//
+// 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.
+//
+
+#if SECURITY_DEP
+
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+using MX = MonoSecurity::Mono.Security.X509;
+#else
+using MX = Mono.Security.X509;
+#endif
+
+using System.Collections;
+using System.Text;
+
+namespace System.Security.Cryptography.X509Certificates {
+
+ internal class X509ChainImplMono : X509ChainImpl
+ {
+ private StoreLocation location;
+ private X509ChainElementCollection elements;
+ private X509ChainPolicy policy;
+ private X509ChainStatus[] status;
+
+ static X509ChainStatus[] Empty = new X509ChainStatus [0];
+
+ // RFC3280 variables
+ private int max_path_length;
+ private X500DistinguishedName working_issuer_name;
+// private string working_public_key_algorithm;
+ private AsymmetricAlgorithm working_public_key;
+
+ // other flags
+ private X509ChainElement bce_restriction;
+
+ // constructors
+
+ public X509ChainImplMono ()
+ : this (false)
+ {
+ }
+
+ public X509ChainImplMono (bool useMachineContext)
+ {
+ location = useMachineContext ? StoreLocation.LocalMachine : StoreLocation.CurrentUser;
+ elements = new X509ChainElementCollection ();
+ policy = new X509ChainPolicy ();
+ }
+
+ [MonoTODO ("Mono's X509Chain is fully managed. All handles are invalid.")]
+ public X509ChainImplMono (IntPtr chainContext)
+ {
+ // CryptoAPI compatibility (unmanaged handle)
+ throw new NotSupportedException ();
+ }
+
+ public override bool IsValid {
+ get { return true; }
+ }
+
+ public override IntPtr Handle {
+ get { return IntPtr.Zero; }
+ }
+
+ // properties
+
+ public override X509ChainElementCollection ChainElements {
+ get { return elements; }
+ }
+
+ public override X509ChainPolicy ChainPolicy {
+ get { return policy; }
+ set { policy = value; }
+ }
+
+ public override X509ChainStatus[] ChainStatus {
+ get {
+ if (status == null)
+ return Empty;
+ return status;
+ }
+ }
+
+ // methods
+
+ [MonoTODO ("Not totally RFC3280 compliant, but neither is MS implementation...")]
+ public override bool Build (X509Certificate2 certificate)
+ {
+ if (certificate == null)
+ throw new ArgumentException ("certificate");
+
+ Reset ();
+ X509ChainStatusFlags flag;
+ try {
+ flag = BuildChainFrom (certificate);
+ ValidateChain (flag);
+ }
+ catch (CryptographicException ce) {
+ throw new ArgumentException ("certificate", ce);
+ }
+
+ X509ChainStatusFlags total = X509ChainStatusFlags.NoError;
+ ArrayList list = new ArrayList ();
+ // build "global" ChainStatus from the ChainStatus of every ChainElements
+ foreach (X509ChainElement ce in elements) {
+ foreach (X509ChainStatus cs in ce.ChainElementStatus) {
+ // we MUST avoid duplicates in the "global" list
+ if ((total & cs.Status) != cs.Status) {
+ list.Add (cs);
+ total |= cs.Status;
+ }
+ }
+ }
+ // and if required add some
+ if (flag != X509ChainStatusFlags.NoError) {
+ list.Insert (0, new X509ChainStatus (flag));
+ }
+ status = (X509ChainStatus[]) list.ToArray (typeof (X509ChainStatus));
+
+ // (fast path) this ignore everything we have checked
+ if ((status.Length == 0) || (ChainPolicy.VerificationFlags == X509VerificationFlags.AllFlags))
+ return true;
+
+ bool result = true;
+ // now check if exclude some verification for the "end result" (boolean)
+ foreach (X509ChainStatus cs in status) {
+ switch (cs.Status) {
+ case X509ChainStatusFlags.UntrustedRoot:
+ case X509ChainStatusFlags.PartialChain:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.AllowUnknownCertificateAuthority) != 0);
+ break;
+ case X509ChainStatusFlags.NotTimeValid:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeValid) != 0);
+ break;
+ // FIXME - from here we needs new test cases for all cases
+ case X509ChainStatusFlags.NotTimeNested:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeNested) != 0);
+ break;
+ case X509ChainStatusFlags.InvalidBasicConstraints:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidBasicConstraints) != 0);
+ break;
+ case X509ChainStatusFlags.InvalidPolicyConstraints:
+ case X509ChainStatusFlags.NoIssuanceChainPolicy:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidPolicy) != 0);
+ break;
+ case X509ChainStatusFlags.InvalidNameConstraints:
+ case X509ChainStatusFlags.HasNotSupportedNameConstraint:
+ case X509ChainStatusFlags.HasNotPermittedNameConstraint:
+ case X509ChainStatusFlags.HasExcludedNameConstraint:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidName) != 0);
+ break;
+ case X509ChainStatusFlags.InvalidExtension:
+ // not sure ?!?
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
+ break;
+ //
+ // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreRootRevocationUnknown) != 0)
+ // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreEndRevocationUnknown) != 0)
+ case X509ChainStatusFlags.CtlNotTimeValid:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlNotTimeValid) != 0);
+ break;
+ case X509ChainStatusFlags.CtlNotSignatureValid:
+ // ?
+ break;
+ // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlSignerRevocationUnknown) != 0);
+ case X509ChainStatusFlags.CtlNotValidForUsage:
+ // FIXME - does IgnoreWrongUsage apply to CTL (it doesn't have Ctl in it's name like the others)
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
+ break;
+ default:
+ result = false;
+ break;
+ }
+ // once we have one failure there's no need to check further
+ if (!result)
+ return false;
+ }
+
+ // every "problem" was excluded
+ return true;
+ }
+
+ public override void Reset ()
+ {
+ // note: this call doesn't Reset the X509ChainPolicy
+ if ((status != null) && (status.Length != 0))
+ status = null;
+ if (elements.Count > 0)
+ elements.Clear ();
+ if (user_root_store != null) {
+ user_root_store.Close ();
+ user_root_store = null;
+ }
+ if (root_store != null) {
+ root_store.Close ();
+ root_store = null;
+ }
+ if (user_ca_store != null) {
+ user_ca_store.Close ();
+ user_ca_store = null;
+ }
+ if (ca_store != null) {
+ ca_store.Close ();
+ ca_store = null;
+ }
+ roots = null;
+ cas = null;
+ collection = null;
+ bce_restriction = null;
+ working_public_key = null;
+ }
+
+ // private stuff
+
+ private X509Certificate2Collection roots;
+ private X509Certificate2Collection cas;
+ private X509Store root_store;
+ private X509Store ca_store;
+ private X509Store user_root_store;
+ private X509Store user_ca_store;
+
+ private X509Certificate2Collection Roots {
+ get {
+ if (roots == null) {
+ X509Certificate2Collection c = new X509Certificate2Collection ();
+ X509Store store = LMRootStore;
+ if (location == StoreLocation.CurrentUser)
+ c.AddRange (UserRootStore.Certificates);
+ c.AddRange (store.Certificates);
+ roots = c;
+ }
+ return roots;
+ }
+ }
+
+ private X509Certificate2Collection CertificateAuthorities {
+ get {
+ if (cas == null) {
+ X509Certificate2Collection c = new X509Certificate2Collection ();
+ X509Store store = LMCAStore;
+ if (location == StoreLocation.CurrentUser)
+ c.AddRange (UserCAStore.Certificates);
+ c.AddRange (store.Certificates);
+ cas = c;
+ }
+ return cas;
+ }
+ }
+
+ private X509Store LMRootStore {
+ get {
+ if (root_store == null) {
+ root_store = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
+ try {
+ root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
+ } catch {
+ }
+ }
+ return root_store;
+ }
+ }
+
+ private X509Store UserRootStore {
+ get {
+ if (user_root_store == null) {
+ user_root_store = new X509Store (StoreName.Root, StoreLocation.CurrentUser);
+ try {
+ user_root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
+ } catch {
+ }
+ }
+ return user_root_store;
+ }
+ }
+
+ private X509Store LMCAStore {
+ get {
+ if (ca_store == null) {
+ ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.LocalMachine);
+ try {
+ ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
+ } catch {
+ }
+ }
+ return ca_store;
+ }
+ }
+
+ private X509Store UserCAStore {
+ get {
+ if (user_ca_store == null) {
+ user_ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.CurrentUser);
+ try {
+ user_ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
+ } catch {
+ }
+ }
+ return user_ca_store;
+ }
+ }
+ // *** certificate chain/path building stuff ***
+
+ private X509Certificate2Collection collection;
+
+ // we search local user (default) or machine certificate store
+ // and in the extra certificate supplied in ChainPolicy.ExtraStore
+ private X509Certificate2Collection CertificateCollection {
+ get {
+ if (collection == null) {
+ collection = new X509Certificate2Collection (ChainPolicy.ExtraStore);
+ collection.AddRange (Roots);
+ collection.AddRange (CertificateAuthorities);
+ }
+ return collection;
+ }
+ }
+
+ // This is a non-recursive chain/path building algorithm.
+ //
+ // At this stage we only checks for PartialChain, Cyclic and UntrustedRoot errors are they
+ // affect the path building (other errors are verification errors).
+ //
+ // Note that the order match the one we need to match MS and not the one defined in RFC3280,
+ // we also include the trusted root certificate (trust anchor in RFC3280) in the list.
+ // (this isn't an issue, just keep that in mind if you look at the source and the RFC)
+ private X509ChainStatusFlags BuildChainFrom (X509Certificate2 certificate)
+ {
+ elements.Add (certificate);
+
+ while (!IsChainComplete (certificate)) {
+ certificate = FindParent (certificate);
+
+ if (certificate == null)
+ return X509ChainStatusFlags.PartialChain;
+
+ if (elements.Contains (certificate))
+ return X509ChainStatusFlags.Cyclic;
+
+ elements.Add (certificate);
+ }
+
+ // roots may be supplied (e.g. in the ExtraStore) so we need to confirm their
+ // trustiness (what a cute word) in the trusted root collection
+ if (!Roots.Contains (certificate))
+ elements [elements.Count - 1].StatusFlags |= X509ChainStatusFlags.UntrustedRoot;
+
+ return X509ChainStatusFlags.NoError;
+ }
+
+
+ private X509Certificate2 SelectBestFromCollection (X509Certificate2 child, X509Certificate2Collection c)
+ {
+ switch (c.Count) {
+ case 0:
+ return null;
+ case 1:
+ return c [0];
+ default:
+ // multiple candidate, keep only the ones that are still valid
+ X509Certificate2Collection time_valid = c.Find (X509FindType.FindByTimeValid, ChainPolicy.VerificationTime, false);
+ switch (time_valid.Count) {
+ case 0:
+ // that's too restrictive, let's revert and try another thing...
+ time_valid = c;
+ break;
+ case 1:
+ return time_valid [0];
+ default:
+ break;
+ }
+
+ // again multiple candidates, let's find the AKI that match the SKI (if we have one)
+ string aki = GetAuthorityKeyIdentifier (child);
+ if (String.IsNullOrEmpty (aki)) {
+ return time_valid [0]; // FIXME: out of luck, you get the first one
+ }
+ foreach (X509Certificate2 parent in time_valid) {
+ string ski = GetSubjectKeyIdentifier (parent);
+ // if both id are available then they must match
+ if (aki == ski)
+ return parent;
+ }
+ return time_valid [0]; // FIXME: out of luck, you get the first one
+ }
+ }
+
+ private X509Certificate2 FindParent (X509Certificate2 certificate)
+ {
+ X509Certificate2Collection subset = CertificateCollection.Find (X509FindType.FindBySubjectDistinguishedName, certificate.Issuer, false);
+ string aki = GetAuthorityKeyIdentifier (certificate);
+ if ((aki != null) && (aki.Length > 0)) {
+ subset.AddRange (CertificateCollection.Find (X509FindType.FindBySubjectKeyIdentifier, aki, false));
+ }
+ X509Certificate2 parent = SelectBestFromCollection (certificate, subset);
+ // if parent==certificate we're looping but it's not (probably) a bug and not a true cyclic (over n certs)
+ return certificate.Equals (parent) ? null : parent;
+ }
+
+ private bool IsChainComplete (X509Certificate2 certificate)
+ {
+ // the chain is complete if we have a self-signed certificate
+ if (!IsSelfIssued (certificate))
+ return false;
+
+ // we're very limited to what we can do without certificate extensions
+ if (certificate.Version < 3)
+ return true;
+
+ // check that Authority Key Identifier == Subject Key Identifier
+ // e.g. it will be different if a self-signed certificate is part (not the end) of the chain
+ string ski = GetSubjectKeyIdentifier (certificate);
+ if (String.IsNullOrEmpty (ski))
+ return true;
+ string aki = GetAuthorityKeyIdentifier (certificate);
+ if (String.IsNullOrEmpty (aki))
+ return true;
+ // if both id are available then they must match
+ return (aki == ski);
+ }
+
+ // check for "self-issued" certificate - without verifying the signature
+ // note that self-issued doesn't always mean it's a root certificate!
+ private bool IsSelfIssued (X509Certificate2 certificate)
+ {
+ return (certificate.Issuer == certificate.Subject);
+ }
+
+
+ // *** certificate chain/path validation stuff ***
+
+ // Currently a subset of RFC3280 (hopefully a full implementation someday)
+ private void ValidateChain (X509ChainStatusFlags flag)
+ {
+ // 'n' should be the root certificate...
+ int n = elements.Count - 1;
+ X509Certificate2 certificate = elements [n].Certificate;
+
+ // ... and, if so, must be treated outside the chain...
+ if (((flag & X509ChainStatusFlags.PartialChain) == 0)) {
+ Process (n);
+ // deal with the case where the chain == the root certificate
+ // (which isn't for RFC3280) part of the chain
+ if (n == 0) {
+ elements [0].UncompressFlags ();
+ return;
+ }
+ // skip the root certificate when processing the chain (in 6.1.3)
+ n--;
+ }
+ // ... unless the chain is a partial one (then we start with that one)
+
+ // 6.1.1 - Inputs
+ // 6.1.1.a - a prospective certificate path of length n (i.e. elements)
+ // 6.1.1.b - the current date/time (i.e. ChainPolicy.VerificationTime)
+ // 6.1.1.c - user-initial-policy-set (i.e. ChainPolicy.CertificatePolicy)
+ // 6.1.1.d - the trust anchor information (i.e. certificate, unless it's a partial chain)
+ // 6.1.1.e - initial-policy-mapping-inhibit (NOT SUPPORTED BY THE API)
+ // 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY THE API)
+ // 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED BY THE API)
+
+ // 6.1.2 - Initialization (incomplete)
+ // 6.1.2.a-f - policy stuff, some TODO, some not supported
+ // 6.1.2.g - working public key algorithm
+// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
+ // 6.1.2.h-i - our key contains both the "working public key" and "working public key parameters" data
+ working_public_key = certificate.PublicKey.Key;
+ // 6.1.2.j - working issuer name
+ working_issuer_name = certificate.IssuerName;
+ // 6.1.2.k - this integer is initialized to n, is decremented for each non-self-issued, certificate and
+ // may be reduced to the value in the path length constraint field
+ max_path_length = n;
+
+ // 6.1.3 - Basic Certificate Processing
+ // note: loop looks reversed (the list is) but we process this part just like RFC3280 does
+ for (int i = n; i > 0; i--) {
+ Process (i);
+ // 6.1.4 - preparation for certificate i+1 (for not with i+1, or i-1 in our loop)
+ PrepareForNextCertificate (i);
+ }
+ Process (0);
+
+ // 6.1.3.a.3 - revocation checks
+ CheckRevocationOnChain (flag);
+
+ // 6.1.5 - Wrap-up procedure
+ WrapUp ();
+ }
+
+ private void Process (int n)
+ {
+ X509ChainElement element = elements [n];
+ X509Certificate2 certificate = element.Certificate;
+
+ // pre-step: DSA certificates may inherit the parameters of their CA
+ if ((n != elements.Count - 1) && (certificate.MonoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) {
+ if (certificate.MonoCertificate.KeyAlgorithmParameters == null) {
+ X509Certificate2 parent = elements [n+1].Certificate;
+ certificate.MonoCertificate.KeyAlgorithmParameters = parent.MonoCertificate.KeyAlgorithmParameters;
+ }
+ }
+
+ bool root = (working_public_key == null);
+ // 6.1.3.a.1 - check signature (with special case to deal with root certificates)
+ if (!IsSignedWith (certificate, root ? certificate.PublicKey.Key : working_public_key)) {
+ // another special case where only an end-entity is available and can't be verified.
+ // In this case we do not report an invalid signature (since this is unknown)
+ if (root || (n != elements.Count - 1) || IsSelfIssued (certificate)) {
+ element.StatusFlags |= X509ChainStatusFlags.NotSignatureValid;
+ }
+ }
+
+ // 6.1.3.a.2 - check validity period
+ if ((ChainPolicy.VerificationTime < certificate.NotBefore) ||
+ (ChainPolicy.VerificationTime > certificate.NotAfter)) {
+ element.StatusFlags |= X509ChainStatusFlags.NotTimeValid;
+ }
+ // TODO - for X509ChainStatusFlags.NotTimeNested (needs global structure)
+
+ // note: most of them don't apply to the root certificate
+ if (root) {
+ return;
+ }
+
+ // 6.1.3.a.3 - revocation check (we're doing at the last stage)
+ // note: you revoke a trusted root by removing it from your trusted store (i.e. no CRL can do this job)
+
+ // 6.1.3.a.4 - check certificate issuer name
+ if (!X500DistinguishedName.AreEqual (certificate.IssuerName, working_issuer_name)) {
+ // NOTE: this is not the "right" error flag, but it's the closest one defined
+ element.StatusFlags |= X509ChainStatusFlags.InvalidNameConstraints;
+ }
+
+ if (!IsSelfIssued (certificate) && (n != 0)) {
+ // TODO 6.1.3.b - subject name in the permitted_subtrees ...
+ // TODO 6.1.3.c - subject name not within excluded_subtrees...
+
+ // TODO - check for X509ChainStatusFlags.InvalidNameConstraint
+ // TODO - check for X509ChainStatusFlags.HasNotSupportedNameConstraint
+ // TODO - check for X509ChainStatusFlags.HasNotPermittedNameConstraint
+ // TODO - check for X509ChainStatusFlags.HasExcludedNameConstraint
+ }
+
+ // TODO 6.1.3.d - check if certificate policies extension is present
+ //if (false) {
+ // TODO - for X509ChainStatusFlags.InvalidPolicyConstraints
+ // using X509ChainPolicy.ApplicationPolicy and X509ChainPolicy.CertificatePolicy
+
+ // TODO - check for X509ChainStatusFlags.NoIssuanceChainPolicy
+
+ //} else {
+ // TODO 6.1.3.e - set valid_policy_tree to NULL
+ //}
+
+ // TODO 6.1.3.f - verify explict_policy > 0 if valid_policy_tree != NULL
+ }
+
+ // CTL == Certificate Trust List / NOT SUPPORTED
+ // TODO - check for X509ChainStatusFlags.CtlNotTimeValid
+ // TODO - check for X509ChainStatusFlags.CtlNotSignatureValid
+ // TODO - check for X509ChainStatusFlags.CtlNotValidForUsage
+
+ private void PrepareForNextCertificate (int n)
+ {
+ X509ChainElement element = elements [n];
+ X509Certificate2 certificate = element.Certificate;
+
+ // TODO 6.1.4.a-b
+
+ // 6.1.4.c
+ working_issuer_name = certificate.SubjectName;
+ // 6.1.4.d-e - our key includes both the public key and it's parameters
+ working_public_key = certificate.PublicKey.Key;
+ // 6.1.4.f
+// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
+
+ // TODO 6.1.4.g-j
+
+ // 6.1.4.k - Verify that the certificate is a CA certificate
+ X509BasicConstraintsExtension bce = (certificate.Extensions["2.5.29.19"] as X509BasicConstraintsExtension);
+ if (bce != null) {
+ if (!bce.CertificateAuthority) {
+ element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
+ }
+ } else if (certificate.Version >= 3) {
+ // recent (v3+) CA certificates must include BCE
+ element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
+ }
+
+ // 6.1.4.l - if the certificate isn't self-issued...
+ if (!IsSelfIssued (certificate)) {
+ // ... verify that max_path_length > 0
+ if (max_path_length > 0) {
+ max_path_length--;
+ } else {
+ // to match MS the reported status must be against the certificate
+ // with the BCE and not where the path is too long. It also means
+ // that this condition has to be reported only once
+ if (bce_restriction != null) {
+ bce_restriction.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
+ }
+ }
+ }
+
+ // 6.1.4.m - if pathLengthConstraint is present...
+ if ((bce != null) && (bce.HasPathLengthConstraint)) {
+ // ... and is less that max_path_length, set max_path_length to it's value
+ if (bce.PathLengthConstraint < max_path_length) {
+ max_path_length = bce.PathLengthConstraint;
+ bce_restriction = element;
+ }
+ }
+
+ // 6.1.4.n - if key usage extension is present...
+ X509KeyUsageExtension kue = (certificate.Extensions["2.5.29.15"] as X509KeyUsageExtension);
+ if (kue != null) {
+ // ... verify keyCertSign is set
+ X509KeyUsageFlags success = X509KeyUsageFlags.KeyCertSign;
+ if ((kue.KeyUsages & success) != success)
+ element.StatusFlags |= X509ChainStatusFlags.NotValidForUsage;
+ }
+
+ // 6.1.4.o - recognize and process other critical extension present in the certificate
+ ProcessCertificateExtensions (element);
+ }
+
+ private void WrapUp ()
+ {
+ X509ChainElement element = elements [0];
+ X509Certificate2 certificate = element.Certificate;
+
+ // 6.1.5.a - TODO if certificate n (our 0) wasn't self issued and explicit_policy != 0
+ if (IsSelfIssued (certificate)) {
+ // TODO... decrement explicit_policy by 1
+ }
+
+ // 6.1.5.b - TODO
+
+ // 6.1.5.c,d,e - not required by the X509Chain implementation
+
+ // 6.1.5.f - recognize and process other critical extension present in the certificate
+ ProcessCertificateExtensions (element);
+
+ // 6.1.5.g - TODO
+
+ // uncompressed the flags into several elements
+ for (int i = elements.Count - 1; i >= 0; i--) {
+ elements [i].UncompressFlags ();
+ }
+ }
+
+ private void ProcessCertificateExtensions (X509ChainElement element)
+ {
+ foreach (X509Extension ext in element.Certificate.Extensions) {
+ if (ext.Critical) {
+ switch (ext.Oid.Value) {
+ case "2.5.29.15": // X509KeyUsageExtension
+ case "2.5.29.19": // X509BasicConstraintsExtension
+ // we processed this extension
+ break;
+ default:
+ // note: Under Windows XP MS implementation seems to ignore
+ // certificate with unknown critical extensions.
+ element.StatusFlags |= X509ChainStatusFlags.InvalidExtension;
+ break;
+ }
+ }
+ }
+ }
+
+ private bool IsSignedWith (X509Certificate2 signed, AsymmetricAlgorithm pubkey)
+ {
+ if (pubkey == null)
+ return false;
+ // Sadly X509Certificate2 doesn't expose the signature nor the tbs (to be signed) structure
+ MX.X509Certificate mx = signed.MonoCertificate;
+ return (mx.VerifySignature (pubkey));
+ }
+
+ private string GetSubjectKeyIdentifier (X509Certificate2 certificate)
+ {
+ X509SubjectKeyIdentifierExtension ski = (certificate.Extensions["2.5.29.14"] as X509SubjectKeyIdentifierExtension);
+ return (ski == null) ? String.Empty : ski.SubjectKeyIdentifier;
+ }
+
+ // System.dll v2 doesn't have a class to deal with the AuthorityKeyIdentifier extension
+ static string GetAuthorityKeyIdentifier (X509Certificate2 certificate)
+ {
+ return GetAuthorityKeyIdentifier (certificate.MonoCertificate.Extensions ["2.5.29.35"]);
+ }
+
+ // but anyway System.dll v2 doesn't expose CRL in any way so...
+ static string GetAuthorityKeyIdentifier (MX.X509Crl crl)
+ {
+ return GetAuthorityKeyIdentifier (crl.Extensions ["2.5.29.35"]);
+ }
+
+ static string GetAuthorityKeyIdentifier (MX.X509Extension ext)
+ {
+ if (ext == null)
+ return String.Empty;
+ MX.Extensions.AuthorityKeyIdentifierExtension aki = new MX.Extensions.AuthorityKeyIdentifierExtension (ext);
+ byte[] id = aki.Identifier;
+ if (id == null)
+ return String.Empty;
+ StringBuilder sb = new StringBuilder ();
+ foreach (byte b in id)
+ sb.Append (b.ToString ("X02"));
+ return sb.ToString ();
+ }
+
+ // we check the revocation only once we have built the complete chain
+ private void CheckRevocationOnChain (X509ChainStatusFlags flag)
+ {
+ bool partial = ((flag & X509ChainStatusFlags.PartialChain) != 0);
+ bool online;
+
+ switch (ChainPolicy.RevocationMode) {
+ case X509RevocationMode.Online:
+ // default
+ online = true;
+ break;
+ case X509RevocationMode.Offline:
+ online = false;
+ break;
+ case X509RevocationMode.NoCheck:
+ return;
+ default:
+ throw new InvalidOperationException (Locale.GetText ("Invalid revocation mode."));
+ }
+
+ bool unknown = partial;
+ // from the root down to the end-entity
+ for (int i = elements.Count - 1; i >= 0; i--) {
+ bool check = true;
+
+ switch (ChainPolicy.RevocationFlag) {
+ case X509RevocationFlag.EndCertificateOnly:
+ check = (i == 0);
+ break;
+ case X509RevocationFlag.EntireChain:
+ check = true;
+ break;
+ case X509RevocationFlag.ExcludeRoot:
+ // default
+ check = (i != (elements.Count - 1));
+ // anyway, who's gonna sign that the root is invalid ?
+ break;
+ }
+
+ X509ChainElement element = elements [i];
+
+ // we can't assume the revocation status if the certificate is bad (e.g. invalid signature)
+ if (!unknown)
+ unknown |= ((element.StatusFlags & X509ChainStatusFlags.NotSignatureValid) != 0);
+
+ if (unknown) {
+ // we can skip the revocation checks as we can't be sure of them anyway
+ element.StatusFlags |= X509ChainStatusFlags.RevocationStatusUnknown;
+ element.StatusFlags |= X509ChainStatusFlags.OfflineRevocation;
+ } else if (check && !partial && !IsSelfIssued (element.Certificate)) {
+ // check for revocation (except for the trusted root and self-issued certs)
+ element.StatusFlags |= CheckRevocation (element.Certificate, i+1, online);
+ // if revoked, then all others following in the chain are unknown...
+ unknown |= ((element.StatusFlags & X509ChainStatusFlags.Revoked) != 0);
+ }
+ }
+ }
+
+ // This isn't how RFC3280 (section 6.3) deals with CRL, but then we don't (yet) support DP, deltas...
+ private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, int ca, bool online)
+ {
+ X509ChainStatusFlags result = X509ChainStatusFlags.RevocationStatusUnknown;
+ X509ChainElement element = elements [ca];
+ X509Certificate2 ca_cert = element.Certificate;
+
+ // find the CRL from the "right" CA
+ while (IsSelfIssued (ca_cert) && (ca < elements.Count - 1)) {
+ // try with this self-issued
+ result = CheckRevocation (certificate, ca_cert, online);
+ if (result != X509ChainStatusFlags.RevocationStatusUnknown)
+ break;
+ ca++;
+ element = elements [ca];
+ ca_cert = element.Certificate;
+ }
+ if (result == X509ChainStatusFlags.RevocationStatusUnknown)
+ result = CheckRevocation (certificate, ca_cert, online);
+ return result;
+ }
+
+ private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, X509Certificate2 ca_cert, bool online)
+ {
+ // change this if/when we support OCSP
+ X509KeyUsageExtension kue = (ca_cert.Extensions["2.5.29.15"] as X509KeyUsageExtension);
+ if (kue != null) {
+ // ... verify CrlSign is set
+ X509KeyUsageFlags success = X509KeyUsageFlags.CrlSign;
+ if ((kue.KeyUsages & success) != success) {
+ // FIXME - we should try to find an alternative CA that has the CrlSign bit
+ return X509ChainStatusFlags.RevocationStatusUnknown;
+ }
+ }
+
+ MX.X509Crl crl = FindCrl (ca_cert);
+
+ if ((crl == null) && online) {
+ // FIXME - download and install new CRL
+ // then you get a second chance
+ // crl = FindCrl (ca_cert, ref valid, ref out_of_date);
+
+ // We need to get the subjectAltName and an URI from there (or use OCSP)
+ // X509KeyUsageExtension subjectAltName = (ca_cert.Extensions["2.5.29.17"] as X509KeyUsageExtension);
+ }
+
+ if (crl != null) {
+ // validate the digital signature on the CRL using the CA public key
+ // note #1: we can't use X509Crl.VerifySignature(X509Certificate) because it duplicates
+ // checks and we loose the "why" of the failure
+ // note #2: we do this before other tests as an invalid signature could be a hacked CRL
+ // (so anything within can't be trusted)
+ if (!crl.VerifySignature (ca_cert.PublicKey.Key)) {
+ return X509ChainStatusFlags.RevocationStatusUnknown;
+ }
+
+ MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry (certificate.MonoCertificate);
+ if (entry != null) {
+ // We have an entry for this CRL that includes an unknown CRITICAL extension
+ // See [X.509 7.3] NOTE 4
+ if (!ProcessCrlEntryExtensions (entry))
+ return X509ChainStatusFlags.Revoked;
+
+ // FIXME - a little more is involved
+ if (entry.RevocationDate <= ChainPolicy.VerificationTime)
+ return X509ChainStatusFlags.Revoked;
+ }
+
+ // are we overdue for a CRL update ? if so we can't be sure of any certificate status
+ if (crl.NextUpdate < ChainPolicy.VerificationTime)
+ return X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation;
+
+ // we have a CRL that includes an unknown CRITICAL extension
+ // we put this check at the end so we do not "hide" any Revoked flags
+ if (!ProcessCrlExtensions (crl)) {
+ return X509ChainStatusFlags.RevocationStatusUnknown;
+ }
+ } else {
+ return X509ChainStatusFlags.RevocationStatusUnknown;
+ }
+
+ return X509ChainStatusFlags.NoError;
+ }
+
+ static MX.X509Crl CheckCrls (string subject, string ski, MX.X509Store store)
+ {
+ if (store == null)
+ return null;
+
+ var crls = store.Crls;
+ foreach (MX.X509Crl crl in crls) {
+ if (crl.IssuerName == subject && (ski.Length == 0 || ski == GetAuthorityKeyIdentifier (crl)))
+ return crl;
+ }
+ return null; // No CRL found
+ }
+
+ private MX.X509Crl FindCrl (X509Certificate2 caCertificate)
+ {
+ string subject = caCertificate.SubjectName.Decode (X500DistinguishedNameFlags.None);
+ string ski = GetSubjectKeyIdentifier (caCertificate);
+
+ // consider that the LocalMachine directories could not exists... and cannot be created by the user
+ MX.X509Crl result = CheckCrls (subject, ski, LMCAStore.Store);
+ if (result != null)
+ return result;
+ if (location == StoreLocation.CurrentUser) {
+ result = CheckCrls (subject, ski, UserCAStore.Store);
+ if (result != null)
+ return result;
+ }
+
+ // consider that the LocalMachine directories could not exists... and cannot be created by the user
+ result = CheckCrls (subject, ski, LMRootStore.Store);
+ if (result != null)
+ return result;
+ if (location == StoreLocation.CurrentUser) {
+ result = CheckCrls (subject, ski, UserRootStore.Store);
+ if (result != null)
+ return result;
+ }
+ return null;
+ }
+
+ private bool ProcessCrlExtensions (MX.X509Crl crl)
+ {
+ foreach (MX.X509Extension ext in crl.Extensions) {
+ if (ext.Critical) {
+ switch (ext.Oid) {
+ case "2.5.29.20": // cRLNumber
+ case "2.5.29.35": // authorityKeyIdentifier
+ // we processed/know about this extension
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private bool ProcessCrlEntryExtensions (MX.X509Crl.X509CrlEntry entry)
+ {
+ foreach (MX.X509Extension ext in entry.Extensions) {
+ if (ext.Critical) {
+ switch (ext.Oid) {
+ case "2.5.29.21": // cRLReason
+ // we processed/know about this extension
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+}
+#endif
--- /dev/null
+//
+// X509Helper2.cs
+//
+// Authors:
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
+//
+// 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.
+//
+#if SECURITY_DEP
+namespace System.Security.Cryptography.X509Certificates
+{
+ internal static class X509Helper2
+ {
+ internal static void ThrowIfContextInvalid (X509CertificateImpl impl)
+ {
+ X509Helper.ThrowIfContextInvalid (impl);
+ }
+
+ internal static X509Certificate2Impl Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
+ {
+ var impl = new X509Certificate2ImplMono ();
+ impl.Import (rawData, password, keyStorageFlags);
+ return impl;
+ }
+
+ internal static X509Certificate2Impl Import (X509Certificate cert)
+ {
+ var impl2 = cert.Impl as X509Certificate2Impl;
+ if (impl2 != null)
+ return (X509Certificate2Impl)impl2.Clone ();
+ return Import (cert.GetRawCertData (), null, X509KeyStorageFlags.DefaultKeySet);
+ }
+
+ internal static X509ChainImpl CreateChainImpl (bool useMachineContext)
+ {
+ return new X509ChainImplMono (useMachineContext);
+ }
+
+ public static bool IsValid (X509ChainImpl impl)
+ {
+ return impl != null && impl.IsValid;
+ }
+
+ internal static void ThrowIfContextInvalid (X509ChainImpl impl)
+ {
+ if (!IsValid (impl))
+ throw GetInvalidChainContextException ();
+ }
+
+ internal static Exception GetInvalidChainContextException ()
+ {
+ return new CryptographicException (Locale.GetText ("Chain instance is empty."));
+ }
+ }
+}
+#endif
namespace System.Security.Cryptography.X509Certificates {
- public sealed class X509Store : IDisposable {
+ public sealed class X509Store {
private string _name;
private StoreLocation _location;
_location = storeLocation;
}
- public void Dispose ()
- {
- }
-
// properties
public X509Certificate2Collection Certificates {
System.Security.Cryptography.X509Certificates/X509Certificate2Collection.cs
System.Security.Cryptography.X509Certificates/X509Certificate2.cs
System.Security.Cryptography.X509Certificates/X509Certificate2Enumerator.cs
+System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs
+System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs
System.Security.Cryptography.X509Certificates/X509CertificateCollection.cs
System.Security.Cryptography.X509Certificates/X509Chain.cs
System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
System.Security.Cryptography.X509Certificates/X509ChainElement.cs
System.Security.Cryptography.X509Certificates/X509ChainElementEnumerator.cs
+System.Security.Cryptography.X509Certificates/X509ChainImpl.cs
+System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs
System.Security.Cryptography.X509Certificates/X509ChainPolicy.cs
System.Security.Cryptography.X509Certificates/X509ChainStatus.cs
System.Security.Cryptography.X509Certificates/X509ChainStatusFlags.cs
System.Security.Cryptography.X509Certificates/X509ExtensionEnumerator.cs
System.Security.Cryptography.X509Certificates/X509FindType.cs
System.Security.Cryptography.X509Certificates/X509IncludeOption.cs
+System.Security.Cryptography.X509Certificates/X509Helper2.cs
System.Security.Cryptography.X509Certificates/X509KeyUsageExtension.cs
System.Security.Cryptography.X509Certificates/X509KeyUsageFlags.cs
System.Security.Cryptography.X509Certificates/X509NameType.cs
public static MyNetworkStream CreateNS (int port)
{
- return CreateNS (port, 5000);
+ return CreateNS (IPAddress.Loopback, port, 5000);
}
public static MyNetworkStream CreateNS (int port, int timeout_ms)
+ {
+ return CreateNS (IPAddress.Loopback, port, timeout_ms);
+ }
+
+ public static MyNetworkStream CreateNS (IPAddress ip, int port)
+ {
+ return CreateNS (ip, port, 5000);
+ }
+
+ public static MyNetworkStream CreateNS (IPAddress ip, int port, int timeout_ms)
{
Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- sock.Connect (new IPEndPoint (IPAddress.Loopback, port));
+ sock.Connect (new IPEndPoint (ip, port));
sock.SendTimeout = timeout_ms;
sock.ReceiveTimeout = timeout_ms;
return new MyNetworkStream (sock);
using System.Net;
using System.Net.Sockets;
using System.Text;
+using System.Collections.Generic;
using NUnit.Framework;
listener.Close ();
}
+ [Test]
+ public void HttpRequestIsLocal ()
+ {
+ var ips = new List<IPAddress> (Dns.GetHostAddresses (Dns.GetHostName ()));
+ ips.Add (IPAddress.Loopback);
+ foreach (var ip in ips) {
+ if (ip.AddressFamily != AddressFamily.InterNetwork)
+ continue;
+
+ HttpListener listener = HttpListener2Test.CreateAndStartListener (
+ "http://" + ip + ":9000/HttpRequestIsLocal/");
+ NetworkStream ns = HttpListener2Test.CreateNS (ip, 9000);
+ HttpListener2Test.Send (ns, "GET /HttpRequestIsLocal/ HTTP/1.0\r\n\r\n");
+ HttpListenerContext ctx = listener.GetContext ();
+ HttpListenerRequest request = ctx.Request;
+ Assert.AreEqual (true, request.IsLocal, "IP " + ip + " is not local");
+ listener.Close ();
+ }
+ }
+
[Test] // #29927
public void HttpRequestUriUnescape ()
{
}
[Test]
- [ExpectedException (typeof (ArgumentException))]
public void GetNameInfo_Invalid_True ()
{
- new X509Certificate2 ().GetNameInfo ((X509NameType) Int32.MinValue, true);
+ try {
+ // MS throws ArgumentException, Mono's new implementation throws
+ // CryptographicException, which is consistent with other "certificate
+ // instance is empty" situations.
+ new X509Certificate2 ().GetNameInfo ((X509NameType) Int32.MinValue, true);
+ Assert.Fail ("Expected exception.");
+ } catch (ArgumentException) {
+ } catch (CryptographicException) {
+ } catch (Exception ex) {
+ Assert.Fail ("Expected 'ArgumentException' or 'CryptographicException', got '{0}'", ex.GetType ());
+ }
}
[Test]
- [ExpectedException (typeof (ArgumentException))]
public void GetNameInfo_Invalid_False ()
{
- new X509Certificate2 ().GetNameInfo ((X509NameType) Int32.MinValue, false);
+ try {
+ // MS throws ArgumentException, Mono's new implementation throws
+ // CryptographicException, which is consistent with other "certificate
+ // instance is empty" situations.
+ new X509Certificate2 ().GetNameInfo ((X509NameType) Int32.MinValue, false);
+ Assert.Fail ("Expected exception.");
+ } catch (ArgumentException) {
+ } catch (CryptographicException) {
+ } catch (Exception ex) {
+ Assert.Fail ("Expected 'ArgumentException' or 'CryptographicException', got '{0}'", ex.GetType ());
+ }
}
[Test]
}
[Test]
- [ExpectedException (typeof (NullReferenceException))]
public void Empty_GetNameInfo_DnsName ()
{
- new X509Certificate2 ().GetNameInfo (X509NameType.DnsName, true);
+ try {
+ // MS throws NullReferenceException, Mono's new implementation throws
+ // CryptographicException, which is consistent with other "certificate
+ // instance is empty" situations.
+ new X509Certificate2 ().GetNameInfo (X509NameType.DnsName, true);
+ Assert.Fail ("Expected exception.");
+ } catch (NullReferenceException) {
+ } catch (CryptographicException) {
+ } catch (Exception ex) {
+ Assert.Fail ("Expected 'NullReferenceException' or 'CryptographicException', got '{0}'", ex.GetType ());
+ }
}
[Test]
System.Security.Cryptography.X509Certificates/X509Certificate2.cs
System.Security.Cryptography.X509Certificates/X509Certificate2Collection.cs
System.Security.Cryptography.X509Certificates/X509Certificate2Enumerator.cs
+System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs
+System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs
System.Security.Cryptography.X509Certificates/X509CertificateCollection.cs
System.Security.Cryptography.X509Certificates/X509Chain.cs
System.Security.Cryptography.X509Certificates/X509ChainElement.cs
System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
System.Security.Cryptography.X509Certificates/X509ChainElementEnumerator.cs
+System.Security.Cryptography.X509Certificates/X509ChainImpl.cs
+System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs
System.Security.Cryptography.X509Certificates/X509ChainPolicy.cs
System.Security.Cryptography.X509Certificates/X509ChainStatus.cs
System.Security.Cryptography.X509Certificates/X509ChainStatusFlags.cs
System.Security.Cryptography.X509Certificates/X509ExtensionEnumerator.cs
System.Security.Cryptography.X509Certificates/X509FindType.cs
System.Security.Cryptography.X509Certificates/X509IncludeOption.cs
+System.Security.Cryptography.X509Certificates/X509Helper2.cs
System.Security.Cryptography.X509Certificates/X509KeyUsageExtension.cs
System.Security.Cryptography.X509Certificates/X509KeyUsageFlags.cs
System.Security.Cryptography.X509Certificates/X509NameType.cs
#include mobile_System.dll.sources
MonoTouch/MonoPInvokeCallbackAttribute.cs
+Assembly/AssemblyInfoEx.cs
+Mono.Net.Security/MonoTlsProviderFactoryExt.cs
+Mono.Security.Interface/MonoTlsProviderFactoryExt.cs
+++ /dev/null
-Mono.Net.Security/MonoTlsProviderFactory.MonoTouch.opt.cs
+++ /dev/null
-#include monotouch_opt_System.dll.sources
+++ /dev/null
-#include monotouch_opt_System.dll.sources
+++ /dev/null
-#include monotouch_opt_System.dll.sources
+++ /dev/null
-#include monotouch_opt_System.dll.sources
+++ /dev/null
-#include monotouch_opt_System.dll.sources
#include mobile_System.dll.sources
+Assembly/AssemblyInfoEx.cs
+Mono.Net.Security/MonoTlsProviderFactoryExt.cs
+Mono.Security.Interface/MonoTlsProviderFactoryExt.cs
#include System.dll.sources
+Assembly/AssemblyInfoEx.cs
+++ /dev/null
-#include xammac_opt_System.dll.sources
+++ /dev/null
-Mono.Net.Security/MonoTlsProviderFactory.MonoTouch.opt.cs
--- /dev/null
+*.g.cs
+generator.exe
--- /dev/null
+// CommonCrypto bindings for MonoMac and MonoTouch
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012-2014 Xamarin Inc.
+
+using System;
+using System.Security.Cryptography;
+using System.Runtime.InteropServices;
+
+namespace Crimson.CommonCrypto {
+
+ // int32_t -> CommonCryptor.h
+ enum CCCryptorStatus {
+ Success = 0,
+ ParamError = -4300,
+ BufferTooSmall = -4301,
+ MemoryFailure = -4302,
+ AlignmentError = -4303,
+ DecodeError = -4304,
+ Unimplemented = -4305
+ }
+
+ // uint32_t -> CommonCryptor.h
+ // note: not exposed publicly so it can stay signed
+ enum CCOperation {
+ Encrypt = 0,
+ Decrypt,
+ }
+
+ // uint32_t -> CommonCryptor.h
+ // note: not exposed publicly so it can stay signed
+ enum CCAlgorithm {
+ AES128 = 0,
+ DES,
+ TripleDES,
+ CAST,
+ RC4,
+ RC2,
+ Blowfish
+ }
+
+ // uint32_t -> CommonCryptor.h
+ // note: not exposed publicly so it can stay signed
+ [Flags]
+ enum CCOptions {
+ None = 0,
+ PKCS7Padding = 1,
+ ECBMode = 2
+ }
+
+ static class Cryptor {
+
+ const string libSystem = "/usr/lib/libSystem.dylib";
+
+ // size_t was changed to IntPtr for 32/64 bits size difference - even if mono is (moslty) used in 32bits only on OSX today
+ // not using `nint` to be able to resue this outside (if needed)
+
+ [DllImport (libSystem)]
+ extern internal static CCCryptorStatus CCCryptorCreate (CCOperation op, CCAlgorithm alg, CCOptions options, /* const void* */ byte[] key, /* size_t */ IntPtr keyLength, /* const void* */ byte[] iv, /* CCCryptorRef* */ ref IntPtr cryptorRef);
+
+ [DllImport (libSystem)]
+ extern internal static CCCryptorStatus CCCryptorRelease (/* CCCryptorRef */ IntPtr cryptorRef);
+
+ [DllImport (libSystem)]
+ extern internal static CCCryptorStatus CCCryptorUpdate (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ byte[] dataIn, /* size_t */ IntPtr dataInLength, /* void* */ byte[] dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
+
+ [DllImport (libSystem)]
+ extern internal static CCCryptorStatus CCCryptorUpdate (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ IntPtr dataIn, /* size_t */ IntPtr dataInLength, /* void* */ IntPtr dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
+
+ [DllImport (libSystem)]
+ extern internal static CCCryptorStatus CCCryptorFinal (/* CCCryptorRef */ IntPtr cryptorRef, /* void* */ byte[] dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
+
+ [DllImport (libSystem)]
+ extern internal static int CCCryptorGetOutputLength (/* CCCryptorRef */ IntPtr cryptorRef, /* size_t */ IntPtr inputLength, bool final);
+
+ [DllImport (libSystem)]
+ extern internal static CCCryptorStatus CCCryptorReset (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ IntPtr iv);
+
+ // helper method to reduce the amount of generate code for each cipher algorithm
+ static internal IntPtr Create (CCOperation operation, CCAlgorithm algorithm, CCOptions options, byte[] key, byte[] iv)
+ {
+ if (key == null)
+ throw new CryptographicException ("A null key was provided");
+
+ // unlike the .NET framework CommonCrypto does not support two-keys triple-des (128 bits) ref: #6967
+ if ((algorithm == CCAlgorithm.TripleDES) && (key.Length == 16)) {
+ byte[] key3 = new byte [24];
+ Buffer.BlockCopy (key, 0, key3, 0, 16);
+ Buffer.BlockCopy (key, 0, key3, 16, 8);
+ key = key3;
+ }
+
+ IntPtr cryptor = IntPtr.Zero;
+ CCCryptorStatus status = Cryptor.CCCryptorCreate (operation, algorithm, options, key, (IntPtr) key.Length, iv, ref cryptor);
+ if (status != CCCryptorStatus.Success)
+ throw new CryptographicUnexpectedOperationException ();
+ return cryptor;
+ }
+
+ // size_t was changed to IntPtr for 32/64 bits size difference - even if mono is (moslty) used in 32bits only on OSX today
+ [DllImport ("/System/Library/Frameworks/Security.framework/Security")]
+ extern internal static /* int */ int SecRandomCopyBytes (/* SecRandomRef */ IntPtr rnd, /* size_t */ IntPtr count, /* uint8_t* */ byte[] bytes);
+
+ static internal void GetRandom (byte[] buffer)
+ {
+ if (SecRandomCopyBytes (IntPtr.Zero, (IntPtr) buffer.Length, buffer) != 0)
+ throw new CryptographicException (Marshal.GetLastWin32Error ()); // errno
+ }
+ }
+
+#if !MONOTOUCH && !XAMMAC
+ static class KeyBuilder {
+ static public byte[] Key (int size)
+ {
+ byte[] buffer = new byte [size];
+ Cryptor.GetRandom (buffer);
+ return buffer;
+ }
+
+ static public byte[] IV (int size)
+ {
+ byte[] buffer = new byte [size];
+ Cryptor.GetRandom (buffer);
+ return buffer;
+ }
+ }
+#endif
+}
--- /dev/null
+//
+// CommonCrypto code generator for symmetric block cipher algorithms
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012 Xamarin Inc.
+//
+
+using System;
+using System.IO;
+
+namespace Xamarin {
+
+ public static class CommonCryptor {
+
+ static public void Generate (string namespaceName, string typeName, string baseTypeName, string ccAlgorithmName, string feedbackSize = "8", string ctorInitializers = null)
+ {
+ string template = @"// Generated file to bind CommonCrypto cipher algorithms - DO NOT EDIT
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012-2014 Xamarin Inc.
+
+using System;
+using System.Security.Cryptography;
+
+using Mono.Security.Cryptography;
+using Crimson.CommonCrypto;
+
+namespace %NAMESPACE% {
+
+ public sealed partial class %TYPE% : %BASE% {
+
+ public %TYPE% ()
+ {
+ FeedbackSizeValue = %FEEDBACKSIZE%;
+ %CTOR_INIT%
+ }
+
+ public override void GenerateIV ()
+ {
+ IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
+ }
+
+ public override void GenerateKey ()
+ {
+ KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
+ }
+
+ public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
+ {
+ IntPtr decryptor = IntPtr.Zero;
+ switch (Mode) {
+ case CipherMode.CBC:
+ decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.%CCALGORITHM%, CCOptions.None, rgbKey, rgbIV);
+ return new FastCryptorTransform (decryptor, this, false, rgbIV);
+ case CipherMode.ECB:
+ decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.%CCALGORITHM%, CCOptions.ECBMode, rgbKey, rgbIV);
+ return new FastCryptorTransform (decryptor, this, false, rgbIV);
+ case CipherMode.CFB:
+#if MONOTOUCH || XAMMAC
+ IntPtr encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.%CCALGORITHM%, CCOptions.ECBMode, rgbKey, rgbIV);
+ decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.%CCALGORITHM%, CCOptions.ECBMode, rgbKey, rgbIV);
+ return new CryptorTransform (decryptor, encryptor, this, false, rgbIV);
+#else
+ throw new CryptographicException (""CFB is not supported by Crimson.CommonCrypto"");
+#endif
+ default:
+ throw new CryptographicException (String.Format (""{0} is not supported by the .NET framework"", Mode));
+ }
+ }
+
+ public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
+ {
+ IntPtr encryptor = IntPtr.Zero;
+ switch (Mode) {
+ case CipherMode.CBC:
+ encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.%CCALGORITHM%, CCOptions.None, rgbKey, rgbIV);
+ return new FastCryptorTransform (encryptor, this, true, rgbIV);
+ case CipherMode.ECB:
+ encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.%CCALGORITHM%, CCOptions.ECBMode, rgbKey, rgbIV);
+ return new FastCryptorTransform (encryptor, this, true, rgbIV);
+ case CipherMode.CFB:
+#if MONOTOUCH || XAMMAC
+ encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.%CCALGORITHM%, CCOptions.ECBMode, rgbKey, rgbIV);
+ return new CryptorTransform (encryptor, IntPtr.Zero, this, true, rgbIV);
+#else
+ throw new CryptographicException (""CFB is not supported by Crimson.CommonCrypto"");
+#endif
+ default:
+ throw new CryptographicException (String.Format (""{0} is not supported by the .NET framework"", Mode));
+ }
+ }
+ }
+}";
+
+ File.WriteAllText (typeName + ".g.cs", template.Replace ("%NAMESPACE%", namespaceName).
+ Replace ("%TYPE%", typeName).Replace ("%BASE%", baseTypeName).Replace("%FEEDBACKSIZE%", feedbackSize).Replace ("%CTOR_INIT%", ctorInitializers).
+ Replace ("%CCALGORITHM%", ccAlgorithmName.ToString ()));
+ }
+ }
+}
--- /dev/null
+//
+// CommonCrypto code generator for digest algorithms
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012-2014 Xamarin Inc.
+//
+
+using System;
+using System.IO;
+
+namespace Xamarin {
+
+ public static class CommonDigest {
+
+#if !MONOTOUCH && !XAMMAC
+ // we do not add anything in MonoTouch, just replacing, so this is not needed
+ // however we can avoid a dependency on Mono.Security for Crimson.CommonCrypto.dll by including the base classes
+ static public void GenerateBaseClass (string namespaceName, string typeName, string baseTypeName, int hashSize,
+ string visibilityStart = "", string visibilityEnd = "")
+ {
+ string template = @"// Generated file to bind CommonCrypto/CommonDigest - DO NOT EDIT
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012-2014 Xamarin Inc.
+
+using System;
+using System.Security.Cryptography;
+using System.Runtime.InteropServices;
+
+namespace %NAMESPACE% {
+
+%VISIBILITY_START%
+ public
+%VISIBILITY_END%
+ abstract class %BASE% : HashAlgorithm {
+
+ protected %BASE% ()
+ {
+ HashSizeValue = %HASHSIZE%;
+ }
+
+ public static new %BASE% Create ()
+ {
+ return Create (""%BASE%"");
+ }
+
+ public static new %BASE% Create (string hashName)
+ {
+ object o = CryptoConfig.CreateFromName (hashName);
+ return (%BASE%) o ?? new %TYPE% ();
+ }
+ }
+}";
+
+ File.WriteAllText (baseTypeName + ".g.cs", template.Replace ("%NAMESPACE%", namespaceName).
+ Replace ("%TYPE%", typeName).Replace ("%BASE%", baseTypeName).
+ Replace ("%VISIBILITY_START%", visibilityStart).Replace ("%VISIBILITY_END%", visibilityEnd).
+ Replace ("%HASHSIZE%", hashSize.ToString ()));
+ }
+#endif
+ static public void Generate (string namespaceName, string typeName, string baseTypeName, int contextSize,
+ string visibilityStart = "", string visibilityEnd = "")
+ {
+ string template = @"// Generated file to bind CommonCrypto/CommonDigest - DO NOT EDIT
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2011-2014 Xamarin Inc.
+
+using System;
+using System.Security.Cryptography;
+using System.Runtime.InteropServices;
+
+using Mono.Security.Cryptography;
+
+namespace %NAMESPACE% {
+
+%VISIBILITY_START%
+ public
+%VISIBILITY_END%
+ sealed class %TYPE% : %BASE% {
+
+ IntPtr ctx;
+
+ [DllImport (""/usr/lib/libSystem.dylib"", EntryPoint=""CC_%BASE%_Init"")]
+ static extern int Init (/* CC_%BASE%_CTX */ IntPtr c);
+
+ [DllImport (""/usr/lib/libSystem.dylib"", EntryPoint=""CC_%BASE%_Update"")]
+ static extern int Update (/* CC_%BASE%_CTX */ IntPtr c, /* const void * */ IntPtr data, /* uint32_t */ uint len);
+
+ [DllImport (""/usr/lib/libSystem.dylib"", EntryPoint=""CC_%BASE%_Final"")]
+ static extern int Final (/* unsigned char * */ byte [] md, /* CC_%BASE%_CTX */ IntPtr c);
+
+ public %TYPE% ()
+ {
+ ctx = IntPtr.Zero;
+ }
+
+ ~%TYPE% ()
+ {
+ Dispose (false);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (ctx != IntPtr.Zero) {
+ Marshal.FreeHGlobal (ctx);
+ ctx = IntPtr.Zero;
+ }
+ base.Dispose (disposing);
+ GC.SuppressFinalize (this);
+ }
+
+ public override void Initialize ()
+ {
+ if (ctx == IntPtr.Zero)
+ ctx = Marshal.AllocHGlobal (%CTX_SIZE%);
+
+ int hr = Init (ctx);
+ if (hr != 1)
+ throw new CryptographicException (hr);
+ }
+
+ protected override void HashCore (byte[] data, int start, int length)
+ {
+ if (ctx == IntPtr.Zero)
+ Initialize ();
+
+ if (data.Length == 0)
+ return;
+
+ unsafe {
+ fixed (byte* p = &data [0]) {
+ int hr = Update (ctx, (IntPtr) (p + start), (uint) length);
+ if (hr != 1)
+ throw new CryptographicException (hr);
+ }
+ }
+ }
+
+ protected override byte[] HashFinal ()
+ {
+ if (ctx == IntPtr.Zero)
+ Initialize ();
+
+ byte[] data = new byte [HashSize >> 3];
+ int hr = Final (data, ctx);
+ if (hr != 1)
+ throw new CryptographicException (hr);
+
+ return data;
+ }
+ }
+}";
+
+ File.WriteAllText (typeName + ".g.cs", template.Replace ("%NAMESPACE%", namespaceName).
+ Replace ("%TYPE%", typeName).Replace ("%BASE%", baseTypeName).
+ Replace ("%VISIBILITY_START%", visibilityStart).Replace ("%VISIBILITY_END%", visibilityEnd).
+ Replace ("%CTX_SIZE%", contextSize.ToString ()));
+ }
+ }
+}
--- /dev/null
+//
+// CorlibExtras.cs: additional stuff not provided by autogenerated code
+//
+// Authors:
+// Sebastien Pouliot (sebastien@xamarun.com)
+//
+// Copyright (C) 2012 Xamarin Inc. All rights reserved.
+//
+
+namespace System.Security.Cryptography {
+
+ // required to ensure compatibility with MS implementation
+ public sealed partial class RC2CryptoServiceProvider : RC2 {
+
+ public override int EffectiveKeySize {
+ get { return base.EffectiveKeySize; }
+ set {
+ if (value != KeySizeValue)
+ throw new CryptographicUnexpectedOperationException ("Effective key size must match key size for compatibility");
+ base.EffectiveKeySize = value;
+ }
+ }
+ }
+}
--- /dev/null
+// ICryptoTransform implementation on top of CommonCrypto and SymmetricTransform
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012 Xamarin Inc.
+
+using System;
+using System.Security.Cryptography;
+
+using Mono.Security.Cryptography;
+
+namespace Crimson.CommonCrypto {
+
+ class CryptorTransform : SymmetricTransform {
+
+ IntPtr handle;
+ IntPtr handle_e;
+ bool encryption;
+
+ public CryptorTransform (IntPtr cryptor, IntPtr special, SymmetricAlgorithm algo, bool encryption, byte[] iv)
+ : base (algo, encryption, iv)
+ {
+ handle = cryptor;
+ // for CFB we need to encrypt data while decrypting
+ handle_e = special;
+ this.encryption = encryption;
+ }
+
+ ~CryptorTransform ()
+ {
+ Dispose (false);
+ }
+
+ // PRO: doing this ensure all cipher modes and padding modes supported by .NET will be available with CommonCrypto (drop-in replacements)
+ // CON: doing this will only process one block at the time, so it's not ideal for performance, but still a lot better than managed
+ protected override void ECB (byte[] input, byte[] output)
+ {
+ IntPtr len = IntPtr.Zero;
+ CCCryptorStatus s = Cryptor.CCCryptorUpdate ((encrypt == encryption) ? handle : handle_e,
+ input, (IntPtr) input.Length, output, (IntPtr) output.Length, ref len);
+ if (((int) len != output.Length) || (s != CCCryptorStatus.Success))
+ throw new CryptographicUnexpectedOperationException (s.ToString ());
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (handle != IntPtr.Zero) {
+ Cryptor.CCCryptorRelease (handle);
+ handle = IntPtr.Zero;
+ }
+ if (handle_e != IntPtr.Zero) {
+ Cryptor.CCCryptorRelease (handle_e);
+ handle_e = IntPtr.Zero;
+ }
+ base.Dispose (disposing);
+ GC.SuppressFinalize (this);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Fast, multi-block, ICryptoTransform implementation on top of CommonCrypto
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012 Xamarin Inc.
+
+using System;
+using System.Security.Cryptography;
+
+using Mono.Security.Cryptography;
+
+namespace Crimson.CommonCrypto {
+
+ unsafe class FastCryptorTransform : ICryptoTransform {
+
+ IntPtr handle;
+ bool encrypt;
+ int BlockSizeByte;
+ byte[] workBuff;
+ bool lastBlock;
+ PaddingMode padding;
+
+ public FastCryptorTransform (IntPtr cryptor, SymmetricAlgorithm algo, bool encryption, byte[] iv)
+ {
+ BlockSizeByte = (algo.BlockSize >> 3);
+
+ if (iv == null) {
+ iv = KeyBuilder.IV (BlockSizeByte);
+ } else if (iv.Length < BlockSizeByte) {
+ string msg = String.Format ("IV is too small ({0} bytes), it should be {1} bytes long.",
+ iv.Length, BlockSizeByte);
+ throw new CryptographicException (msg);
+ }
+
+ handle = cryptor;
+ encrypt = encryption;
+ padding = algo.Padding;
+ // transform buffer
+ workBuff = new byte [BlockSizeByte];
+ }
+
+ ~FastCryptorTransform ()
+ {
+ Dispose (false);
+ }
+
+ public void Dispose ()
+ {
+ Dispose (true);
+ }
+
+ protected virtual void Dispose (bool disposing)
+ {
+ if (handle != IntPtr.Zero) {
+ Cryptor.CCCryptorRelease (handle);
+ handle = IntPtr.Zero;
+ }
+ GC.SuppressFinalize (this);
+ }
+
+ public virtual bool CanTransformMultipleBlocks {
+ get { return true; }
+ }
+
+ public virtual bool CanReuseTransform {
+ get { return false; }
+ }
+
+ public virtual int InputBlockSize {
+ get { return BlockSizeByte; }
+ }
+
+ public virtual int OutputBlockSize {
+ get { return BlockSizeByte; }
+ }
+
+ int Transform (byte[] input, int inputOffset, byte[] output, int outputOffset, int length)
+ {
+ IntPtr len = IntPtr.Zero;
+ IntPtr in_len = (IntPtr) length;
+ IntPtr out_len = (IntPtr) (output.Length - outputOffset);
+ fixed (byte* inputBuffer = &input [0])
+ fixed (byte* outputBuffer = &output [0]) {
+ CCCryptorStatus s = Cryptor.CCCryptorUpdate (handle, (IntPtr) (inputBuffer + inputOffset), in_len, (IntPtr) (outputBuffer + outputOffset), out_len, ref len);
+ if (s != CCCryptorStatus.Success)
+ throw new CryptographicException (s.ToString ());
+ }
+ return (int) len;
+ }
+
+ private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ if (inputBuffer == null)
+ throw new ArgumentNullException ("inputBuffer");
+ if (inputOffset < 0)
+ throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
+ if (inputCount < 0)
+ throw new ArgumentOutOfRangeException ("inputCount", "< 0");
+ // ordered to avoid possible integer overflow
+ if (inputOffset > inputBuffer.Length - inputCount)
+ throw new ArgumentException ("inputBuffer", "Overflow");
+ }
+
+ // this method may get called MANY times so this is the one to optimize
+ public virtual int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+ {
+ CheckInput (inputBuffer, inputOffset, inputCount);
+ // check output parameters
+ if (outputBuffer == null)
+ throw new ArgumentNullException ("outputBuffer");
+ if (outputOffset < 0)
+ throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
+
+ // ordered to avoid possible integer overflow
+ int len = outputBuffer.Length - inputCount - outputOffset;
+ if (!encrypt && (0 > len) && ((padding == PaddingMode.None) || (padding == PaddingMode.Zeros))) {
+ throw new CryptographicException ("outputBuffer", "Overflow");
+ } else if (KeepLastBlock) {
+ if (0 > len + BlockSizeByte) {
+ throw new CryptographicException ("outputBuffer", "Overflow");
+ }
+ } else {
+ if (0 > len) {
+ // there's a special case if this is the end of the decryption process
+ if (inputBuffer.Length - inputOffset - outputBuffer.Length == BlockSizeByte)
+ inputCount = outputBuffer.Length - outputOffset;
+ else
+ throw new CryptographicException ("outputBuffer", "Overflow");
+ }
+ }
+ return InternalTransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
+ }
+
+ private bool KeepLastBlock {
+ get {
+ return ((!encrypt) && (padding != PaddingMode.None) && (padding != PaddingMode.Zeros));
+ }
+ }
+
+ private int InternalTransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+ {
+ int offs = inputOffset;
+ int full;
+
+ // this way we don't do a modulo every time we're called
+ // and we may save a division
+ if (inputCount != BlockSizeByte) {
+ if ((inputCount % BlockSizeByte) != 0)
+ throw new CryptographicException ("Invalid input block size.");
+
+ full = inputCount / BlockSizeByte;
+ } else
+ full = 1;
+
+ if (KeepLastBlock)
+ full--;
+
+ int total = 0;
+
+ if (lastBlock) {
+ Transform (workBuff, 0, outputBuffer, outputOffset, BlockSizeByte);
+ outputOffset += BlockSizeByte;
+ total += BlockSizeByte;
+ lastBlock = false;
+ }
+
+ if (full > 0) {
+ int length = full * BlockSizeByte;
+ Transform (inputBuffer, offs, outputBuffer, outputOffset, length);
+ offs += length;
+ outputOffset += length;
+ total += length;
+ }
+
+ if (KeepLastBlock) {
+ Buffer.BlockCopy (inputBuffer, offs, workBuff, 0, BlockSizeByte);
+ lastBlock = true;
+ }
+
+ return total;
+ }
+
+ private void Random (byte[] buffer, int start, int length)
+ {
+ byte[] random = new byte [length];
+ Cryptor.GetRandom (random);
+ Buffer.BlockCopy (random, 0, buffer, start, length);
+ }
+
+ private void ThrowBadPaddingException (PaddingMode padding, int length, int position)
+ {
+ string msg = String.Format ("Bad {0} padding.", padding);
+ if (length >= 0)
+ msg += String.Format (" Invalid length {0}.", length);
+ if (position >= 0)
+ msg += String.Format (" Error found at position {0}.", position);
+ throw new CryptographicException (msg);
+ }
+
+ private byte[] FinalEncrypt (byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ // are there still full block to process ?
+ int full = (inputCount / BlockSizeByte) * BlockSizeByte;
+ int rem = inputCount - full;
+ int total = full;
+
+ switch (padding) {
+ case PaddingMode.ANSIX923:
+ case PaddingMode.ISO10126:
+ case PaddingMode.PKCS7:
+ // we need to add an extra block for padding
+ total += BlockSizeByte;
+ break;
+ default:
+ if (inputCount == 0)
+ return new byte [0];
+ if (rem != 0) {
+ if (padding == PaddingMode.None)
+ throw new CryptographicException ("invalid block length");
+ // zero padding the input (by adding a block for the partial data)
+ byte[] paddedInput = new byte [full + BlockSizeByte];
+ Buffer.BlockCopy (inputBuffer, inputOffset, paddedInput, 0, inputCount);
+ inputBuffer = paddedInput;
+ inputOffset = 0;
+ inputCount = paddedInput.Length;
+ total = inputCount;
+ }
+ break;
+ }
+
+ byte[] res = new byte [total];
+ int outputOffset = 0;
+
+ // process all blocks except the last (final) block
+ if (total > BlockSizeByte) {
+ outputOffset = InternalTransformBlock (inputBuffer, inputOffset, total - BlockSizeByte, res, 0);
+ inputOffset += outputOffset;
+ }
+
+ // now we only have a single last block to encrypt
+ byte pad = (byte) (BlockSizeByte - rem);
+ switch (padding) {
+ case PaddingMode.ANSIX923:
+ // XX 00 00 00 00 00 00 07 (zero + padding length)
+ res [res.Length - 1] = pad;
+ Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
+ // the last padded block will be transformed in-place
+ InternalTransformBlock (res, full, BlockSizeByte, res, full);
+ break;
+ case PaddingMode.ISO10126:
+ // XX 3F 52 2A 81 AB F7 07 (random + padding length)
+ Random (res, res.Length - pad, pad - 1);
+ res [res.Length - 1] = pad;
+ Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
+ // the last padded block will be transformed in-place
+ InternalTransformBlock (res, full, BlockSizeByte, res, full);
+ break;
+ case PaddingMode.PKCS7:
+ // XX 07 07 07 07 07 07 07 (padding length)
+ for (int i = res.Length; --i >= (res.Length - pad);)
+ res [i] = pad;
+ Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
+ // the last padded block will be transformed in-place
+ InternalTransformBlock (res, full, BlockSizeByte, res, full);
+ break;
+ default:
+ InternalTransformBlock (inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
+ break;
+ }
+ return res;
+ }
+
+ private byte[] FinalDecrypt (byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ if ((inputCount % BlockSizeByte) > 0)
+ throw new CryptographicException ("Invalid input block size.");
+
+ int total = inputCount;
+ if (lastBlock)
+ total += BlockSizeByte;
+
+ byte[] res = new byte [total];
+ int outputOffset = 0;
+
+ if (inputCount > 0)
+ outputOffset = InternalTransformBlock (inputBuffer, inputOffset, inputCount, res, 0);
+
+ if (lastBlock) {
+ Transform (workBuff, 0, res, outputOffset, BlockSizeByte);
+ outputOffset += BlockSizeByte;
+ lastBlock = false;
+ }
+
+ // total may be 0 (e.g. PaddingMode.None)
+ byte pad = ((total > 0) ? res [total - 1] : (byte) 0);
+ switch (padding) {
+ case PaddingMode.ANSIX923:
+ if ((pad == 0) || (pad > BlockSizeByte))
+ ThrowBadPaddingException (padding, pad, -1);
+ for (int i = pad - 1; i > 0; i--) {
+ if (res [total - 1 - i] != 0x00)
+ ThrowBadPaddingException (padding, -1, i);
+ }
+ total -= pad;
+ break;
+ case PaddingMode.ISO10126:
+ if ((pad == 0) || (pad > BlockSizeByte))
+ ThrowBadPaddingException (padding, pad, -1);
+ total -= pad;
+ break;
+ case PaddingMode.PKCS7:
+ if ((pad == 0) || (pad > BlockSizeByte))
+ ThrowBadPaddingException (padding, pad, -1);
+ for (int i = pad - 1; i > 0; i--) {
+ if (res [total - 1 - i] != pad)
+ ThrowBadPaddingException (padding, -1, i);
+ }
+ total -= pad;
+ break;
+ case PaddingMode.None: // nothing to do - it's a multiple of block size
+ case PaddingMode.Zeros: // nothing to do - user must unpad himself
+ break;
+ }
+
+ // return output without padding
+ if (total > 0) {
+ byte[] data = new byte [total];
+ Buffer.BlockCopy (res, 0, data, 0, total);
+ // zeroize decrypted data (copy with padding)
+ Array.Clear (res, 0, res.Length);
+ return data;
+ }
+ else
+ return new byte [0];
+ }
+
+ public virtual byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ CheckInput (inputBuffer, inputOffset, inputCount);
+
+ if (encrypt)
+ return FinalEncrypt (inputBuffer, inputOffset, inputCount);
+ else
+ return FinalDecrypt (inputBuffer, inputOffset, inputCount);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+CommonCrypto/%.g.cs: CommonCrypto/generator.exe
+ cd CommonCrypto && mono --debug generator.exe
+
+CommonCrypto/generator.exe: CommonCrypto/generator.cs CommonCrypto/CommonDigestGenerator.cs CommonCrypto/CommonCryptorGenerator.cs
+ mcs CommonCrypto/generator.cs CommonCrypto/CommonDigestGenerator.cs CommonCrypto/CommonCryptorGenerator.cs -o $@
--- /dev/null
+// A CommonCrypto-based implementation of RC4(tm)
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright 2012-2014 Xamarin Inc.
+
+using System;
+using System.Security.Cryptography;
+
+using Crimson.CommonCrypto;
+
+#if MONOTOUCH || XAMMAC
+using Mono.Security.Cryptography;
+
+namespace Mono.Security.Cryptography {
+
+#if !INSIDE_CORLIB
+ public
+#endif
+ sealed partial class ARC4Managed : RC4, ICryptoTransform {
+
+ IntPtr handle;
+
+ public ARC4Managed ()
+ {
+ }
+
+ ~ARC4Managed ()
+ {
+ Dispose (false);
+ }
+#else
+namespace Crimson.Security.Cryptography {
+
+ public abstract class RC4 : SymmetricAlgorithm {
+
+ private static KeySizes[] s_legalBlockSizes = {
+ new KeySizes (64, 64, 0)
+ };
+
+ private static KeySizes[] s_legalKeySizes = {
+ new KeySizes (40, 512, 8)
+ };
+
+ public RC4 ()
+ {
+ KeySizeValue = 128;
+ BlockSizeValue = 64;
+ FeedbackSizeValue = BlockSizeValue;
+ LegalBlockSizesValue = s_legalBlockSizes;
+ LegalKeySizesValue = s_legalKeySizes;
+ }
+
+ // required for compatibility with .NET 2.0
+ public override byte[] IV {
+ get { return new byte [0]; }
+ set { ; }
+ }
+
+ new static public RC4 Create()
+ {
+ return Create ("RC4");
+ }
+
+ new static public RC4 Create (string algName)
+ {
+ object o = CryptoConfig.CreateFromName (algName);
+ return (RC4) o ?? new RC4CommonCrypto ();
+ }
+ }
+
+ public sealed class RC4CommonCrypto : RC4, ICryptoTransform {
+
+ IntPtr handle;
+
+ public RC4CommonCrypto ()
+ {
+ }
+
+ ~RC4CommonCrypto ()
+ {
+ Dispose (false);
+ }
+#endif
+
+ public bool CanReuseTransform {
+ get { return false; }
+ }
+
+ public bool CanTransformMultipleBlocks {
+ get { return true; }
+ }
+
+ public int InputBlockSize {
+ get { return 1; }
+ }
+
+ public int OutputBlockSize {
+ get { return 1; }
+ }
+
+ public override byte[] Key {
+ get {
+ return base.Key;
+ }
+ set {
+ if (value == null)
+ throw new ArgumentNullException ("Key");
+
+ int length = (value.Length << 3);
+ KeySizeValue = length;
+ KeyValue = (byte[]) value.Clone ();
+ }
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (handle != IntPtr.Zero) {
+ Cryptor.CCCryptorRelease (handle);
+ handle = IntPtr.Zero;
+ }
+ base.Dispose (disposing);
+ GC.SuppressFinalize (this);
+ }
+
+ public override void GenerateIV ()
+ {
+ // not used for a stream cipher
+ IVValue = new byte [0];
+ }
+
+ public override void GenerateKey ()
+ {
+ KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
+ }
+
+ public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
+ {
+ KeyValue = rgbKey;
+ IVValue = rgbIV;
+ return this;
+ }
+
+ public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
+ {
+ KeyValue = rgbKey;
+ IVValue = rgbIV;
+ return this;
+ }
+
+ private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ if (inputBuffer == null)
+ throw new ArgumentNullException ("inputBuffer");
+ if (inputOffset < 0)
+ throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
+ if (inputCount < 0)
+ throw new ArgumentOutOfRangeException ("inputCount", "< 0");
+ // ordered to avoid possible integer overflow
+ if (inputOffset > inputBuffer.Length - inputCount)
+ throw new ArgumentException ("inputBuffer", "Overflow");
+ }
+
+ public unsafe int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+ {
+ CheckInput (inputBuffer, inputOffset, inputCount);
+ if (inputCount == 0)
+ return 0;
+
+ // check output parameters
+ if (outputBuffer == null)
+ throw new ArgumentNullException ("outputBuffer");
+ if (outputOffset < 0)
+ throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
+ // ordered to avoid possible integer overflow
+ if (outputOffset > outputBuffer.Length - inputCount)
+ throw new ArgumentException ("outputBuffer", "Overflow");
+ if (outputBuffer.Length == 0)
+ throw new CryptographicException ("output buffer too small");
+
+ if (handle == IntPtr.Zero)
+ handle = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.RC4, CCOptions.None, KeyValue, IVValue);
+
+ IntPtr len = IntPtr.Zero;
+ IntPtr in_len = (IntPtr) (inputBuffer.Length - inputOffset);
+ IntPtr out_len = (IntPtr) (outputBuffer.Length - outputOffset);
+ fixed (byte* input = &inputBuffer [0])
+ fixed (byte* output = &outputBuffer [0]) {
+ CCCryptorStatus s = Cryptor.CCCryptorUpdate (handle, (IntPtr) (input + inputOffset), in_len, (IntPtr) (output + outputOffset), out_len, ref len);
+ if ((len != out_len) || (s != CCCryptorStatus.Success))
+ throw new CryptographicUnexpectedOperationException (s.ToString ());
+ }
+ return (int) out_len;
+ }
+
+ public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ CheckInput (inputBuffer, inputOffset, inputCount);
+ try {
+ byte[] output = new byte [inputCount];
+ TransformBlock (inputBuffer, inputOffset, inputCount, output, 0);
+ return output;
+ }
+ finally {
+ Cryptor.CCCryptorRelease (handle);
+ handle = IntPtr.Zero;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// RijndaelManaged.cs: Use CommonCrypto AES when possible,
+// fallback on RijndaelManagedTransform otherwise
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012 Xamarin Inc.
+//
+
+using System;
+using System.Security.Cryptography;
+
+using Mono.Security.Cryptography;
+using Crimson.CommonCrypto;
+
+namespace System.Security.Cryptography {
+
+ public sealed class RijndaelManaged : Rijndael {
+
+ public RijndaelManaged ()
+ {
+ }
+
+ public override void GenerateIV ()
+ {
+ IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
+ }
+
+ public override void GenerateKey ()
+ {
+ KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
+ }
+
+ public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
+ {
+ // AES is Rijndael with a 128 bits block size, so we can use CommonCrypto in this case
+ if (BlockSize == 128) {
+ IntPtr decryptor = IntPtr.Zero;
+ switch (Mode) {
+ case CipherMode.CBC:
+ decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.AES128, CCOptions.None, rgbKey, rgbIV);
+ return new FastCryptorTransform (decryptor, this, false, rgbIV);
+ case CipherMode.ECB:
+ decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.AES128, CCOptions.ECBMode, rgbKey, rgbIV);
+ return new FastCryptorTransform (decryptor, this, false, rgbIV);
+ default:
+ // CFB cipher mode is not supported by the (old) API we used (for compatibility) so we fallback for them
+ // FIXME: benchmark if we're better with RijndaelManagedTransform or CryptorTransform for CFB mode
+ break;
+ }
+ }
+
+ return NewEncryptor(rgbKey,
+ ModeValue,
+ rgbIV,
+ FeedbackSizeValue,
+ RijndaelManagedTransformMode.Decrypt);
+ }
+
+ public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
+ {
+ if (BlockSize == 128) {
+ IntPtr encryptor = IntPtr.Zero;
+ switch (Mode) {
+ case CipherMode.CBC:
+ encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.AES128, CCOptions.None, rgbKey, rgbIV);
+ return new FastCryptorTransform (encryptor, this, true, rgbIV);
+ case CipherMode.ECB:
+ encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.AES128, CCOptions.ECBMode, rgbKey, rgbIV);
+ return new FastCryptorTransform (encryptor, this, true, rgbIV);
+ default:
+ // CFB cipher mode is not supported by the (old) API we used (for compatibility) so we fallback for them
+ // FIXME: benchmark if we're better with RijndaelManagedTransform or CryptorTransform for CFB mode
+ break;
+ }
+ }
+
+ return NewEncryptor(rgbKey,
+ ModeValue,
+ rgbIV,
+ FeedbackSizeValue,
+ RijndaelManagedTransformMode.Encrypt);
+ }
+
+
+ private ICryptoTransform NewEncryptor (byte[] rgbKey,
+ CipherMode mode,
+ byte[] rgbIV,
+ int feedbackSize,
+ RijndaelManagedTransformMode encryptMode) {
+ // Build the key if one does not already exist
+ if (rgbKey == null) {
+ rgbKey = Utils.GenerateRandom(KeySizeValue / 8);
+ }
+
+ // If not ECB mode, make sure we have an IV. In CoreCLR we do not support ECB, so we must have
+ // an IV in all cases.
+#if !FEATURE_CRYPTO
+ if (mode != CipherMode.ECB) {
+#endif // !FEATURE_CRYPTO
+ if (rgbIV == null) {
+ rgbIV = Utils.GenerateRandom(BlockSizeValue / 8);
+ }
+#if !FEATURE_CRYPTO
+ }
+#endif // !FEATURE_CRYPTO
+
+ // Create the encryptor/decryptor object
+ return new RijndaelManagedTransform (rgbKey,
+ mode,
+ rgbIV,
+ BlockSizeValue,
+ feedbackSize,
+ PaddingValue,
+ encryptMode);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// SecRandom.cs: based on Mono's System.Security.Cryptography.RNGCryptoServiceProvider
+//
+// Authors:
+// Mark Crichton (crichton@gimp.org)
+// Sebastien Pouliot (sebastien@xamarun.com)
+//
+// (C) 2002
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2012-2014 Xamarin Inc.
+//
+// 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.
+//
+
+using Crimson.CommonCrypto;
+
+// http://developer.apple.com/library/ios/#DOCUMENTATION/Security/Reference/RandomizationReference/Reference/reference.html
+#if MONOTOUCH || XAMMAC
+namespace System.Security.Cryptography {
+ public class RNGCryptoServiceProvider : RandomNumberGenerator {
+ public RNGCryptoServiceProvider ()
+ {
+ }
+
+ ~RNGCryptoServiceProvider ()
+ {
+ }
+#else
+using System;
+using System.Security.Cryptography;
+
+namespace Crimson.Security.Cryptography {
+
+ public class SecRandom : RandomNumberGenerator {
+#endif
+
+ public override void GetBytes (byte[] data)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+
+ Cryptor.GetRandom (data);
+ }
+
+ public override void GetNonZeroBytes (byte[] data)
+ {
+ if (data == null)
+ throw new ArgumentNullException ("data");
+
+ byte[] random = new byte [data.Length * 2];
+ int i = 0;
+ // one pass should be enough but hey this is random ;-)
+ while (i < data.Length) {
+ Cryptor.GetRandom (random);
+ for (int j=0; j < random.Length; j++) {
+ if (i == data.Length)
+ break;
+ if (random [j] != 0)
+ data [i++] = random [j];
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// CommonCrypto Code Generator
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+//
+// Copyright 2012 Xamarin Inc.
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Xamarin {
+
+ class Program {
+ static void Main (string [] args)
+ {
+ // mscorlib replacements
+ CommonDigest.Generate ("System.Security.Cryptography", "MD5CryptoServiceProvider", "MD5", 1000);
+ CommonDigest.Generate ("System.Security.Cryptography", "SHA1CryptoServiceProvider", "SHA1", 1000);
+ CommonDigest.Generate ("System.Security.Cryptography", "SHA1Managed", "SHA1", 1000);
+ CommonDigest.Generate ("System.Security.Cryptography", "SHA256Managed", "SHA256", 1000);
+ CommonDigest.Generate ("System.Security.Cryptography", "SHA384Managed", "SHA384", 1000);
+ CommonDigest.Generate ("System.Security.Cryptography", "SHA512Managed", "SHA512", 1000);
+
+ // System.Core replacements - not yet in MT profile (4.0 - functional dupes anyway)
+ //CommonDigest.Generate ("System.Security.Cryptography", "MD5Cng", "MD5", 1000);
+ //CommonDigest.Generate ("System.Security.Cryptography", "SHA256Cng", "SHA256", 1000);
+ //CommonDigest.Generate ("System.Security.Cryptography", "SHA384Cng", "SHA384", 1000);
+ //CommonDigest.Generate ("System.Security.Cryptography", "SHA512Cng", "SHA512", 1000);
+ //CommonDigest.Generate ("System.Security.Cryptography", "SHA256CryptoServiceProvider", "SHA256", 1000);
+ //CommonDigest.Generate ("System.Security.Cryptography", "SHA384CryptoServiceProvider", "SHA384", 1000);
+ //CommonDigest.Generate ("System.Security.Cryptography", "SHA512CryptoServiceProvider", "SHA512", 1000);
+
+ // Mono.Security replacements
+ CommonDigest.Generate ("Mono.Security.Cryptography", "MD2Managed", "MD2", 1000, "#if !INSIDE_CORLIB", "#endif");
+ CommonDigest.Generate ("Mono.Security.Cryptography", "MD4Managed", "MD4", 1000, "#if !INSIDE_CORLIB", "#endif");
+ CommonDigest.Generate ("Mono.Security.Cryptography", "SHA224Managed", "SHA224", 1000);
+
+ // mscorlib replacements
+ CommonCryptor.Generate ("System.Security.Cryptography", "DESCryptoServiceProvider", "DES", "DES");
+ CommonCryptor.Generate ("System.Security.Cryptography", "TripleDESCryptoServiceProvider", "TripleDES", "TripleDES");
+ CommonCryptor.Generate ("System.Security.Cryptography", "RC2CryptoServiceProvider", "RC2", "RC2", ctorInitializers: "LegalKeySizesValue = new[] { new KeySizes(40, 128, 8) };");
+ // Rijndael supports block sizes that are not available in AES - as such it does not use the same generated code
+ // but has it's own version, using AES (128 bits block size) and falling back to managed (192/256 bits block size)
+
+ // System.Core replacements
+ CommonCryptor.Generate ("System.Security.Cryptography", "AesManaged", "Aes", "AES128", "128");
+ CommonCryptor.Generate ("System.Security.Cryptography", "AesCryptoServiceProvider", "Aes", "AES128");
+
+ // Mono.Security replacements
+ // RC4 is a stream (not a block) cipher so it can not reuse the generated code
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+
+namespace XamMac.CoreFoundation
+{
+ internal static class CFHelpers
+ {
+ internal const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
+ internal const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
+
+ [DllImport (CoreFoundationLibrary)]
+ internal extern static void CFRelease (IntPtr obj);
+
+ [DllImport (CoreFoundationLibrary)]
+ internal extern static IntPtr CFRetain (IntPtr obj);
+
+ [StructLayout (LayoutKind.Sequential)]
+ struct CFRange {
+ public IntPtr loc;
+ public IntPtr len;
+
+ public CFRange (int loc, int len)
+ : this ((long) loc, (long) len)
+ {
+ }
+
+ public CFRange (long l, long len)
+ {
+ this.loc = (IntPtr) l;
+ this.len = (IntPtr) len;
+ }
+ }
+
+ [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
+ extern static IntPtr CFStringCreateWithCharacters (IntPtr allocator, string str, IntPtr count);
+
+ [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
+ extern static IntPtr CFStringGetLength (IntPtr handle);
+
+ [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
+ extern static IntPtr CFStringGetCharactersPtr (IntPtr handle);
+
+ [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
+ extern static IntPtr CFStringGetCharacters (IntPtr handle, CFRange range, IntPtr buffer);
+
+ internal static string FetchString (IntPtr handle)
+ {
+ if (handle == IntPtr.Zero)
+ return null;
+
+ string str;
+
+ int l = (int)CFStringGetLength (handle);
+ IntPtr u = CFStringGetCharactersPtr (handle);
+ IntPtr buffer = IntPtr.Zero;
+ if (u == IntPtr.Zero){
+ CFRange r = new CFRange (0, l);
+ buffer = Marshal.AllocCoTaskMem (l * 2);
+ CFStringGetCharacters (handle, r, buffer);
+ u = buffer;
+ }
+ unsafe {
+ str = new string ((char *) u, 0, l);
+ }
+
+ if (buffer != IntPtr.Zero)
+ Marshal.FreeCoTaskMem (buffer);
+
+ return str;
+ }
+
+ [DllImport (CoreFoundationLibrary)]
+ extern static IntPtr CFDataGetLength (IntPtr handle);
+
+ [DllImport (CoreFoundationLibrary)]
+ extern static IntPtr CFDataGetBytePtr (IntPtr handle);
+
+ internal static byte[] FetchDataBuffer (IntPtr handle)
+ {
+ var length = (int)CFDataGetLength (handle);
+ var buffer = new byte [length];
+ var ptr = CFDataGetBytePtr (handle);
+ Marshal.Copy (ptr, buffer, 0, buffer.Length);
+ return buffer;
+ }
+
+ [DllImport (CoreFoundationLibrary)]
+ extern static IntPtr CFDataCreateWithBytesNoCopy (IntPtr allocator, IntPtr bytes, IntPtr length, IntPtr bytesDeallocator);
+
+ [DllImport (CoreFoundationLibrary)]
+ extern static IntPtr CFDataCreate (IntPtr allocator, IntPtr bytes, IntPtr length);
+
+ [DllImport (SecurityLibrary)]
+ extern static IntPtr SecCertificateCreateWithData (IntPtr allocator, IntPtr cfData);
+
+ unsafe internal static IntPtr CreateCertificateFromData (byte[] data)
+ {
+ fixed (void *ptr = data) {
+ var cfdata = CFDataCreate (IntPtr.Zero, (IntPtr)ptr, new IntPtr (data.Length));
+ if (cfdata == IntPtr.Zero)
+ return IntPtr.Zero;
+
+ var certificate = SecCertificateCreateWithData (IntPtr.Zero, cfdata);
+ if (cfdata != IntPtr.Zero)
+ CFRelease (cfdata);
+ return certificate;
+ }
+ }
+ }
+}
thisdir = class/corlib
SUBDIRS =
include ../../build/rules.make
+include CommonCrypto/Makefile.include
export __SECURITY_BOOTSTRAP_DB=$(topdir)/class/corlib
LIBRARY = corlib.dll
#pragma warning restore 649
#endregion
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern static int GetILOffsetFromFile (string path, int methodToken, uint methodIndex, int nativeOffset);
-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern static bool get_frame_info (int skip, bool needFileInfo, out MethodBase method,
out int iloffset, out int native_offset,
else
sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> {2}", frame.GetMethodAddress (), frame.GetNativeOffset (), unknown);
} else {
- GetFullNameForStackTrace (sb, frame.GetMethod ());
+ StackTraceHelper.GetFullNameForStackTrace (sb, frame.GetMethod ());
if (frame.GetILOffset () == -1) {
sb.AppendFormat (" <0x{0:x5} + 0x{1:x5}>", frame.GetMethodAddress (), frame.GetNativeOffset ());
return i != 0;
}
- // This method is also used with reflection by mono-symbolicate tool.
- // mono-symbolicate tool uses this method to check which method matches
- // the stack frame method signature.
- static void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi)
- {
- var declaringType = mi.DeclaringType;
- if (declaringType.IsGenericType && !declaringType.IsGenericTypeDefinition)
- declaringType = declaringType.GetGenericTypeDefinition ();
-
- // Get generic definition
- var bindingflags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
- foreach (var m in declaringType.GetMethods (bindingflags)) {
- if (m.MetadataToken == mi.MetadataToken) {
- mi = m;
- break;
- }
- }
-
- sb.Append (declaringType.ToString ());
-
- sb.Append (".");
- sb.Append (mi.Name);
-
- if (mi.IsGenericMethod) {
- Type[] gen_params = mi.GetGenericArguments ();
- sb.Append ("[");
- for (int j = 0; j < gen_params.Length; j++) {
- if (j > 0)
- sb.Append (",");
- sb.Append (gen_params [j].Name);
- }
- sb.Append ("]");
- }
-
- ParameterInfo[] p = mi.GetParametersInternal ();
-
- sb.Append (" (");
- for (int i = 0; i < p.Length; ++i) {
- if (i > 0)
- sb.Append (", ");
-
- Type pt = p[i].ParameterType;
- if (pt.IsGenericType && ! pt.IsGenericTypeDefinition)
- pt = pt.GetGenericTypeDefinition ();
-
- if (pt.IsClass && !String.IsNullOrEmpty (pt.Namespace)) {
- sb.Append (pt.Namespace);
- sb.Append (".");
- }
- sb.Append (pt.Name);
- if (p [i].Name != null) {
- sb.Append (" ");
- sb.Append (p [i].Name);
- }
- }
- sb.Append (")");
- }
-
public override string ToString ()
{
StringBuilder sb = new StringBuilder ();
--- /dev/null
+//
+// System.Diagnostics.StackTraceHelper.cs
+//
+// Author:
+// Marcos Henrich (marcos.henrich@xamarin.com)
+//
+// Copyright (C) Xamarin, Inc (http://www.xamarin.com)
+//
+// 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.
+//
+
+using System.Text;
+using System.Reflection;
+
+namespace System.Diagnostics {
+
+ // This class exists so tools such as mono-symbolicate can use it directly.
+ class StackTraceHelper {
+
+ public static void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi)
+ {
+ var declaringType = mi.DeclaringType;
+ if (declaringType.IsGenericType && !declaringType.IsGenericTypeDefinition)
+ declaringType = declaringType.GetGenericTypeDefinition ();
+
+ // Get generic definition
+ var bindingflags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
+ foreach (var m in declaringType.GetMethods (bindingflags)) {
+ if (m.MetadataToken == mi.MetadataToken) {
+ mi = m;
+ break;
+ }
+ }
+
+ sb.Append (declaringType.ToString ());
+
+ sb.Append (".");
+ sb.Append (mi.Name);
+
+ if (mi.IsGenericMethod) {
+ Type[] gen_params = mi.GetGenericArguments ();
+ sb.Append ("[");
+ for (int j = 0; j < gen_params.Length; j++) {
+ if (j > 0)
+ sb.Append (",");
+ sb.Append (gen_params [j].Name);
+ }
+ sb.Append ("]");
+ }
+
+ ParameterInfo[] p = mi.GetParameters ();
+
+ sb.Append (" (");
+ for (int i = 0; i < p.Length; ++i) {
+ if (i > 0)
+ sb.Append (", ");
+
+ Type pt = p[i].ParameterType;
+ if (pt.IsGenericType && ! pt.IsGenericTypeDefinition)
+ pt = pt.GetGenericTypeDefinition ();
+
+ if (pt.IsClass && !String.IsNullOrEmpty (pt.Namespace)) {
+ sb.Append (pt.Namespace);
+ sb.Append (".");
+ }
+ sb.Append (pt.Name);
+ if (p [i].Name != null) {
+ sb.Append (" ");
+ sb.Append (p [i].Name);
+ }
+ }
+ sb.Append (")");
+ }
+ }
+}
public sealed class FileInfo : FileSystemInfo
{
private bool exists;
+ private string displayPath;
public FileInfo (string fileName)
{
OriginalPath = fileName;
FullPath = Path.GetFullPath (fileName);
+
+ displayPath = OriginalPath;
}
private FileInfo (SerializationInfo info, StreamingContext context)
: base (info, context)
{
+ displayPath = OriginalPath;
}
internal override void InternalRefresh ()
File.Move (FullPath, destFullPath);
this.FullPath = destFullPath;
+
+ displayPath = destFileName;
}
public FileInfo CopyTo (string destFileName)
public override string ToString ()
{
- return OriginalPath;
+ return displayPath;
}
#if !MOBILE
//
using System;
+using System.Threading;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public void Free()
{
- FreeHandle(handle);
- handle = 0;
+ // Copy the handle instance member to a local variable. This is required to prevent
+ // race conditions releasing the handle.
+ int local_handle = handle;
+
+ // Free the handle if it hasn't already been freed.
+ if (local_handle != 0 && Interlocked.CompareExchange (ref handle, 0, local_handle) == local_handle) {
+ FreeHandle (local_handle);
+ }
+ else {
+ throw new InvalidOperationException ("Handle is not initialized.");
+ }
}
public static explicit operator IntPtr (GCHandle value)
public static explicit operator GCHandle(IntPtr value)
{
if (value == IntPtr.Zero)
- throw new ArgumentException ("GCHandle value cannot be zero");
+ throw new InvalidOperationException ("GCHandle value cannot be zero");
if (!CheckCurrentDomain ((int)value))
throw new ArgumentException ("GCHandle value belongs to a different domain");
return new GCHandle (value);
impl = X509Helper.InitFromHandle (handle);
}
+ internal X509Certificate (X509CertificateImpl impl)
+ {
+ if (impl == null)
+ throw new ArgumentNullException ("impl");
+
+ this.impl = X509Helper.InitFromCertificate (impl);
+ }
+
public X509Certificate (System.Security.Cryptography.X509Certificates.X509Certificate cert)
{
if (cert == null)
hideDates = false;
}
+ internal void ImportHandle (X509CertificateImpl impl)
+ {
+ Reset ();
+ this.impl = impl;
+ }
+
+ internal X509CertificateImpl Impl {
+ get {
+ X509Helper.ThrowIfContextInvalid (impl);
+ return impl;
+ }
+ }
+
+ internal bool IsValid {
+ get { return X509Helper.IsValid (impl); }
+ }
+
+ internal void ThrowIfContextInvalid ()
+ {
+ X509Helper.ThrowIfContextInvalid (impl);
+ }
// public methods
return null;
X509Helper.ThrowIfContextInvalid (impl);
- return impl.GetEffectiveDateString ().ToString ();
+ return impl.GetValidFrom ().ToLocalTime ().ToString ();
}
// strangly there are no DateTime returning function
return null;
X509Helper.ThrowIfContextInvalid (impl);
- return impl.GetExpirationDateString ().ToString ();
+ return impl.GetValidUntil ().ToLocalTime ().ToString ();
}
// well maybe someday there'll be support for PGP or SPKI ?
public abstract X509CertificateImpl Clone ();
- public abstract string GetSubjectSummary ();
-
public abstract string GetIssuerName (bool legacyV1Mode);
public abstract string GetSubjectName (bool legacyV1Mode);
public abstract byte[] GetRawCertData ();
- public abstract DateTime GetEffectiveDateString ();
+ public abstract DateTime GetValidFrom ();
- public abstract DateTime GetExpirationDateString ();
+ public abstract DateTime GetValidUntil ();
byte[] cachedCertificateHash;
--- /dev/null
+using System;
+using System.Text;
+using System.Runtime.InteropServices;
+using XamMac.CoreFoundation;
+using MX = Mono.Security.X509;
+
+namespace System.Security.Cryptography.X509Certificates
+{
+ class X509CertificateImplApple : X509CertificateImpl
+ {
+ IntPtr handle;
+ X509CertificateImpl fallback;
+
+ public X509CertificateImplApple (IntPtr handle, bool owns)
+ {
+ this.handle = handle;
+ if (!owns)
+ CFHelpers.CFRetain (handle);
+ }
+
+ public override bool IsValid {
+ get { return handle != IntPtr.Zero; }
+ }
+
+ public override IntPtr Handle {
+ get { return handle; }
+ }
+
+ public override X509CertificateImpl Clone ()
+ {
+ ThrowIfContextInvalid ();
+ return new X509CertificateImplApple (handle, false);
+ }
+
+ [DllImport (CFHelpers.SecurityLibrary)]
+ extern static IntPtr SecCertificateCopySubjectSummary (IntPtr cert);
+
+ [DllImport (CFHelpers.SecurityLibrary)]
+ extern static IntPtr SecCertificateCopyData (IntPtr cert);
+
+ public override byte[] GetRawCertData ()
+ {
+ ThrowIfContextInvalid ();
+ var data = SecCertificateCopyData (handle);
+ if (data == IntPtr.Zero)
+ throw new ArgumentException ("Not a valid certificate");
+
+ try {
+ return CFHelpers.FetchDataBuffer (data);
+ } finally {
+ CFHelpers.CFRelease (data);
+ }
+ }
+
+ public override string GetSubjectSummary ()
+ {
+ ThrowIfContextInvalid ();
+ IntPtr cfstr = SecCertificateCopySubjectSummary (handle);
+ string ret = CFHelpers.FetchString (cfstr);
+ CFHelpers.CFRelease (cfstr);
+ return ret;
+ }
+
+ protected override byte[] GetCertHash (bool lazy)
+ {
+ // FIXME: might just return 'null' when 'lazy' is true.
+ ThrowIfContextInvalid ();
+ SHA1 sha = SHA1.Create ();
+ return sha.ComputeHash (GetRawCertData ());
+ }
+
+ public override bool Equals (X509CertificateImpl other, out bool result)
+ {
+ var otherAppleImpl = other as X509CertificateImplApple;
+ if (otherAppleImpl != null && otherAppleImpl.handle == handle) {
+ result = true;
+ return true;
+ }
+
+ result = false;
+ return false;
+ }
+
+ void MustFallback ()
+ {
+ ThrowIfContextInvalid ();
+ if (fallback != null)
+ return;
+ var mxCert = new MX.X509Certificate (GetRawCertData ());
+ fallback = new X509CertificateImplMono (mxCert);
+ }
+
+ public X509CertificateImpl FallbackImpl {
+ get {
+ MustFallback ();
+ return fallback;
+ }
+ }
+
+ public override string GetSubjectName (bool legacyV1Mode)
+ {
+ return FallbackImpl.GetSubjectName (legacyV1Mode);
+ }
+
+ public override string GetIssuerName (bool legacyV1Mode)
+ {
+ return FallbackImpl.GetIssuerName (legacyV1Mode);
+ }
+
+ public override DateTime GetEffectiveDateString ()
+ {
+ return FallbackImpl.GetEffectiveDateString ();
+ }
+
+ public override DateTime GetExpirationDateString ()
+ {
+ return FallbackImpl.GetExpirationDateString ();
+ }
+
+ public override string GetKeyAlgorithm ()
+ {
+ return FallbackImpl.GetKeyAlgorithm ();
+ }
+
+ public override byte[] GetKeyAlgorithmParameters ()
+ {
+ return FallbackImpl.GetKeyAlgorithmParameters ();
+ }
+
+ public override byte[] GetPublicKey ()
+ {
+ return FallbackImpl.GetPublicKey ();
+ }
+
+ public override byte[] GetSerialNumber ()
+ {
+ return FallbackImpl.GetSerialNumber ();
+ }
+
+ public override byte[] Export (X509ContentType contentType, byte[] password)
+ {
+ ThrowIfContextInvalid ();
+
+ switch (contentType) {
+ case X509ContentType.Cert:
+ return GetRawCertData ();
+ case X509ContentType.Pfx: // this includes Pkcs12
+ // TODO
+ throw new NotSupportedException ();
+ case X509ContentType.SerializedCert:
+ // TODO
+ throw new NotSupportedException ();
+ default:
+ string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
+ throw new CryptographicException (msg);
+ }
+ }
+
+ public override string ToString (bool full)
+ {
+ ThrowIfContextInvalid ();
+
+ if (!full || fallback == null) {
+ var summary = GetSubjectSummary ();
+ return string.Format ("[X509Certificate: {0}]", summary);
+ }
+
+ string nl = Environment.NewLine;
+ StringBuilder sb = new StringBuilder ();
+ sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
+
+ sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
+ sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetEffectiveDateString ());
+ sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetExpirationDateString ());
+ sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
+
+ sb.Append (nl);
+ return sb.ToString ();
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (handle != IntPtr.Zero){
+ CFHelpers.CFRelease (handle);
+ handle = IntPtr.Zero;
+ }
+ if (fallback != null) {
+ fallback.Dispose ();
+ fallback = null;
+ }
+ }
+ }
+}
return MX.X501.ToString (x509.GetIssuerName (), true, ", ", true);
}
- public override string GetSubjectSummary ()
- {
- ThrowIfContextInvalid ();
- return x509.SubjectName;
- }
-
public override string GetSubjectName (bool legacyV1Mode)
{
ThrowIfContextInvalid ();
return sha.ComputeHash (x509.RawData);
}
- public override DateTime GetEffectiveDateString ()
+ public override DateTime GetValidFrom ()
{
ThrowIfContextInvalid ();
- return x509.ValidFrom.ToLocalTime ();
+ return x509.ValidFrom;
}
- public override DateTime GetExpirationDateString ()
+ public override DateTime GetValidUntil ()
{
ThrowIfContextInvalid ();
- return x509.ValidUntil.ToLocalTime ();
+ return x509.ValidUntil;
}
public override bool Equals (X509CertificateImpl other, out bool result)
StringBuilder sb = new StringBuilder ();
sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
- sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetEffectiveDateString ());
- sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetExpirationDateString ());
+ sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
+ sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
sb.Append (nl);
return sb.ToString ();
--- /dev/null
+using System;
+using System.Runtime.InteropServices;
+using MX = Mono.Security.X509;
+using XamMac.CoreFoundation;
+
+namespace System.Security.Cryptography.X509Certificates
+{
+ static partial class X509Helper
+ {
+ public static X509CertificateImpl InitFromHandle (IntPtr handle)
+ {
+ return new X509CertificateImplApple (handle, false);
+ }
+
+ public static X509CertificateImpl Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
+ {
+ MX.X509Certificate x509;
+ IntPtr handle;
+ if (password == null) {
+ handle = CFHelpers.CreateCertificateFromData (rawData);
+ if (handle != IntPtr.Zero)
+ return new X509CertificateImplApple (handle, true);
+
+ try {
+ x509 = new MX.X509Certificate (rawData);
+ } catch (Exception e) {
+ try {
+ x509 = X509Helper.ImportPkcs12 (rawData, null);
+ } catch {
+ string msg = Locale.GetText ("Unable to decode certificate.");
+ // inner exception is the original (not second) exception
+ throw new CryptographicException (msg, e);
+ }
+ }
+ } else {
+ // try PKCS#12
+ try {
+ x509 = X509Helper.ImportPkcs12 (rawData, password);
+ }
+ catch {
+ // it's possible to supply a (unrequired/unusued) password
+ // fix bug #79028
+ x509 = new MX.X509Certificate (rawData);
+ }
+ }
+
+ return new X509CertificateImplMono (x509);
+ }
+ }
+}
+++ /dev/null
-#if MONOTOUCH || XAMMAC
-
-// this file is a shim to enable compiling monotouch profiles without mono-extensions
-namespace System.Security.Cryptography.X509Certificates
-{
- static partial class X509Helper
- {
- public static X509CertificateImpl InitFromHandle (IntPtr handle)
- {
- throw new NotSupportedException ();
- }
-
- public static X509CertificateImpl Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
- {
- throw new NotSupportedException ();
- }
- }
-}
-
-#endif
--- /dev/null
+using System;
+
+namespace System.Text {
+
+ internal static partial class EncodingHelper {
+
+ static volatile Encoding utf8Encoding;
+
+ internal static Encoding UTF8 {
+ get {
+ if (utf8Encoding == null) {
+ lock (lockobj){
+ if (utf8Encoding == null){
+ utf8Encoding = new UTF8Encoding (true, false);
+ utf8Encoding.setReadOnly ();
+ }
+ }
+ }
+
+ return utf8Encoding;
+ }
+ }
+
+ // The mobile profile has been default'ing to UTF8 since it's creation
+ internal static Encoding GetDefaultEncoding ()
+ {
+ return UTF8;
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-#if MONOTOUCH
-
-// this file is a shim to enable compiling monotouch profiles without mono-extensions
-namespace System.Text
-{
- internal static partial class EncodingHelper
- {
- internal static Encoding GetDefaultEncoding ()
- {
- throw new NotSupportedException ();
- }
- }
-}
-
-#endif
static Console ()
{
-#if NET_2_1
- Encoding inputEncoding;
- Encoding outputEncoding;
-#endif
-
if (Environment.IsRunningOnWindows) {
//
// On Windows, follow the Windows tradition
#endif
-#if !NET_2_1
// FIXME: Console should use these encodings when changed
static Encoding inputEncoding;
static Encoding outputEncoding;
}
}
+#if !NET_2_1
public static ConsoleColor BackgroundColor {
get { return ConsoleDriver.BackgroundColor; }
set { ConsoleDriver.BackgroundColor = value; }
+++ /dev/null
-#if MONOTOUCH
-
-// this file is a shim to enable compiling monotouch profiles without mono-extensions
-namespace System
-{
- public static partial class Environment
- {
- public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
- {
- throw new NotSupportedException ();
- }
-
- internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
- {
- throw new NotSupportedException ();
- }
- }
-}
-
-#endif
--- /dev/null
+// Copyright 2014 Xamarin Inc.
+
+// note: or older hack to give the Documents (or Library) directories
+
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace System {
+
+ public static partial class Environment {
+
+ static string ns_document;
+ static string ns_library;
+
+ [DllImport ("__Internal")]
+ extern static string xamarin_GetFolderPath (int folder);
+
+ static string NSDocumentDirectory {
+ get {
+ if (ns_document == null) {
+#if MONOTOUCH_TV
+ // The "normal" NSDocumentDirectory is a read-only directory on tvOS
+ // and that breaks a lot of assumptions in the runtime and the BCL
+ // to avoid this we relocate the Documents directory under Caches
+ ns_document = Path.Combine (NSLibraryDirectory, "Caches", "Documents");
+ if (!Directory.Exists (ns_document))
+ Directory.CreateDirectory (ns_document);
+#else
+ ns_document = xamarin_GetFolderPath (/* NSDocumentDirectory */ 9);
+#endif
+ }
+ return ns_document;
+ }
+ }
+
+ // Various user-visible documentation, support, and configuration files
+ static string NSLibraryDirectory {
+ get {
+ if (ns_library == null)
+ ns_library = xamarin_GetFolderPath (/* NSLibraryDirectory */ 5);
+ return ns_library;
+ }
+ }
+
+ public static string GetFolderPath (SpecialFolder folder, SpecialFolderOption option)
+ {
+ return UnixGetFolderPath (folder, option);
+ }
+
+ // needed by our BCL, e.g. IsolatedStorageFile.cs
+ internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
+ {
+ var dir = iOSGetFolderPath (folder);
+ if ((option == SpecialFolderOption.Create) && !Directory.Exists (dir))
+ Directory.CreateDirectory (dir);
+ return dir;
+ }
+
+ internal static string iOSGetFolderPath (SpecialFolder folder)
+ {
+ switch (folder) {
+ case SpecialFolder.MyComputer:
+ case SpecialFolder.Programs:
+ case SpecialFolder.SendTo:
+ case SpecialFolder.StartMenu:
+ case SpecialFolder.Startup:
+ case SpecialFolder.Cookies:
+ case SpecialFolder.History:
+ case SpecialFolder.Recent:
+ case SpecialFolder.CommonProgramFiles:
+ case SpecialFolder.System:
+ case SpecialFolder.NetworkShortcuts:
+ case SpecialFolder.CommonStartMenu:
+ case SpecialFolder.CommonPrograms:
+ case SpecialFolder.CommonStartup:
+ case SpecialFolder.CommonDesktopDirectory:
+ case SpecialFolder.PrinterShortcuts:
+ case SpecialFolder.Windows:
+ case SpecialFolder.SystemX86:
+ case SpecialFolder.ProgramFilesX86:
+ case SpecialFolder.CommonProgramFilesX86:
+ case SpecialFolder.CommonDocuments:
+ case SpecialFolder.CommonAdminTools:
+ case SpecialFolder.AdminTools:
+ case SpecialFolder.CommonMusic:
+ case SpecialFolder.CommonPictures:
+ case SpecialFolder.CommonVideos:
+ case SpecialFolder.LocalizedResources:
+ case SpecialFolder.CommonOemLinks:
+ case SpecialFolder.CDBurning:
+ return String.Empty;
+
+ // personal == ~
+ case SpecialFolder.Personal:
+ case SpecialFolder.LocalApplicationData:
+ return NSDocumentDirectory;
+
+ case SpecialFolder.ApplicationData:
+ // note: at first glance that looked like a good place to return NSLibraryDirectory
+ // but it would break isolated storage for existing applications
+ return Path.Combine (NSDocumentDirectory, ".config");
+
+ case SpecialFolder.Resources:
+ return NSLibraryDirectory; // older (8.2 and previous) would return String.Empty
+
+ case SpecialFolder.Desktop:
+ case SpecialFolder.DesktopDirectory:
+ return Path.Combine (NSDocumentDirectory, "Desktop");
+
+ case SpecialFolder.MyMusic:
+ return Path.Combine (NSDocumentDirectory, "Music");
+
+ case SpecialFolder.MyPictures:
+ return Path.Combine (NSDocumentDirectory, "Pictures");
+
+ case SpecialFolder.Templates:
+ return Path.Combine (NSDocumentDirectory, "Templates");
+
+ case SpecialFolder.MyVideos:
+ return Path.Combine (NSDocumentDirectory, "Videos");
+
+ case SpecialFolder.CommonTemplates:
+ return "/usr/share/templates";
+
+ case SpecialFolder.Fonts:
+ return Path.Combine (NSDocumentDirectory, ".fonts");
+
+ case SpecialFolder.Favorites:
+ return Path.Combine (NSLibraryDirectory, "Favorites");
+
+ case SpecialFolder.ProgramFiles:
+ return "/Applications";
+
+ case SpecialFolder.InternetCache:
+ return Path.Combine (NSLibraryDirectory, "Caches");
+
+ case SpecialFolder.UserProfile:
+ return internalGetHome ();
+
+ case SpecialFolder.CommonApplicationData:
+ return "/usr/share";
+
+ default:
+ throw new ArgumentException ("Invalid SpecialFolder");
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+#if MONOTOUCH && FULL_AOT_RUNTIME
+
+using Crimson.CommonCrypto;
+
+namespace System
+{
+ partial struct Guid
+ {
+ public static Guid NewGuid ()
+ {
+ byte[] b = new byte [16];
+ Cryptor.GetRandom (b);
+
+ Guid res = new Guid (b);
+ // Mask in Variant 1-0 in Bit[7..6]
+ res._d = (byte) ((res._d & 0x3fu) | 0x80u);
+ // Mask in Version 4 (random based Guid) in Bits[15..13]
+ res._c = (short) ((res._c & 0x0fffu) | 0x4000u);
+
+ return res;
+ }
+ }
+}
+
+#endif
\ No newline at end of file
+++ /dev/null
-#if MONOTOUCH && FULL_AOT_RUNTIME
-
-// this file is a shim to enable compiling monotouch profiles without mono-extensions
-namespace System
-{
- partial struct Guid
- {
- public static Guid NewGuid ()
- {
- throw new NotSupportedException ();
- }
- }
-}
-
-#endif
--- /dev/null
+namespace System {
+
+ public partial class NotSupportedException {
+
+ // Avoid having the linker generate this method for every linked build
+ // It also fix #30075 where --linkskip=mscorlib means that method could not be added
+ // but still referenced from other assemblies
+ internal static Exception LinkedAway ()
+ {
+ return new NotSupportedException ("Linked Away");
+ }
+ }
+}
\ No newline at end of file
}
}
+ [Test] //Covers #38796
+ public void ToStringAfterMoveTo ()
+ {
+ string name1 = "FIT.ToStringAfterMoveTo.Test";
+ string name2 = "FIT.ToStringAfterMoveTo.Test.Alt";
+ string path1 = TempFolder + DSC + name1;
+ string path2 = TempFolder + DSC + name2;
+ DeleteFile (path1);
+ DeleteFile (path2);
+
+ try {
+ File.Create (path1).Close ();
+ FileInfo info = new FileInfo (path1);
+ Assert.AreEqual (path1, info.ToString (), "#A");
+
+ info.MoveTo (path2);
+ Assert.AreEqual (path2, info.ToString (), "#B");
+ } finally {
+ DeleteFile (path1);
+ DeleteFile (path2);
+ }
+ }
+
#if !MOBILE
[Test]
public void Replace1 ()
System.Diagnostics/Debugger.cs
System.Diagnostics/StackFrame.cs
System.Diagnostics/StackTrace.cs
+System.Diagnostics/StackTraceHelper.cs
System.Diagnostics.Tracing/EventAttribute.cs
System.Diagnostics.Tracing/EventCommand.cs
System.Diagnostics.Tracing/EventSource.cs
--- /dev/null
+System.Security.Cryptography/MD5CryptoServiceProvider.cs
+System.Security.Cryptography/SHA1CryptoServiceProvider.cs
+System.Security.Cryptography/SHA1CryptoServiceProvider.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/descryptoserviceprovider.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/rc2cryptoserviceprovider.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/rijndaelmanaged.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/sha1managed.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/sha256managed.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/sha384managed.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/sha512managed.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/tripledescryptoserviceprovider.cs
+System.Security.Cryptography/RNGCryptoServiceProvider.cs
+../Mono.Security/Mono.Security.Cryptography/ARC4Managed.cs
+../Mono.Security/Mono.Security.Cryptography/MD2Managed.cs
+../Mono.Security/Mono.Security.Cryptography/MD4Managed.cs
#include corlib.dll.sources
+CommonCrypto/CommonCrypto.cs
+CommonCrypto/CryptorTransform.cs
+CommonCrypto/FastCryptorTransform.cs
+CommonCrypto/CorlibExtras.cs
+CommonCrypto/MD5CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1Managed.g.cs
+CommonCrypto/SHA256Managed.g.cs
+CommonCrypto/SHA384Managed.g.cs
+CommonCrypto/SHA512Managed.g.cs
+CommonCrypto/TripleDESCryptoServiceProvider.g.cs
+CommonCrypto/DESCryptoServiceProvider.g.cs
+CommonCrypto/RC2CryptoServiceProvider.g.cs
+CommonCrypto/RijndaelManaged.cs
+CommonCrypto/SecRandom.cs
+CommonCrypto/RC4CommonCrypto.cs
+CommonCrypto/MD2Managed.g.cs
+CommonCrypto/MD4Managed.g.cs
+System/Environment.iOS.cs
+System/Guid.MonoTouch.cs
+System/NotSupportedException.iOS.cs
+CoreFoundation/CFHelpers.cs
+System.Security.Cryptography.X509Certificates/X509CertificateImplApple.cs
+System.Security.Cryptography.X509Certificates/X509Helper.Apple.cs
+System.Text/EncodingHelper.MonoTouch.cs
+++ /dev/null
-System/Environment.MonoTouch.opt.cs
-System/Guid.MonoTouch.opt.cs
-System.Text/EncodingHelper.MonoTouch.opt.cs
-System.Security.Cryptography.X509Certificates/X509Helper.MonoTouch.opt.cs
--- /dev/null
+#include monotouch_corlib.dll.exclude.sources
#include corlib.dll.sources
+CommonCrypto/CommonCrypto.cs
+CommonCrypto/CryptorTransform.cs
+CommonCrypto/FastCryptorTransform.cs
+CommonCrypto/CorlibExtras.cs
+CommonCrypto/MD5CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1Managed.g.cs
+CommonCrypto/SHA256Managed.g.cs
+CommonCrypto/SHA384Managed.g.cs
+CommonCrypto/SHA512Managed.g.cs
+CommonCrypto/TripleDESCryptoServiceProvider.g.cs
+CommonCrypto/DESCryptoServiceProvider.g.cs
+CommonCrypto/RC2CryptoServiceProvider.g.cs
+CommonCrypto/RijndaelManaged.cs
+CommonCrypto/SecRandom.cs
+CommonCrypto/RC4CommonCrypto.cs
+CommonCrypto/MD2Managed.g.cs
+CommonCrypto/MD4Managed.g.cs
+System/Environment.iOS.cs
+System/Guid.MonoTouch.cs
+System/NotSupportedException.iOS.cs
+CoreFoundation/CFHelpers.cs
+System.Security.Cryptography.X509Certificates/X509CertificateImplApple.cs
+System.Security.Cryptography.X509Certificates/X509Helper.Apple.cs
+System.Text/EncodingHelper.MonoTouch.cs
+++ /dev/null
-#include monotouch_opt_corlib.dll.sources
--- /dev/null
+#include monotouch_corlib.dll.exclude.sources
#include corlib.dll.sources
+CommonCrypto/CommonCrypto.cs
+CommonCrypto/CryptorTransform.cs
+CommonCrypto/FastCryptorTransform.cs
+CommonCrypto/CorlibExtras.cs
+CommonCrypto/MD5CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1Managed.g.cs
+CommonCrypto/SHA256Managed.g.cs
+CommonCrypto/SHA384Managed.g.cs
+CommonCrypto/SHA512Managed.g.cs
+CommonCrypto/TripleDESCryptoServiceProvider.g.cs
+CommonCrypto/DESCryptoServiceProvider.g.cs
+CommonCrypto/RC2CryptoServiceProvider.g.cs
+CommonCrypto/RijndaelManaged.cs
+CommonCrypto/SecRandom.cs
+CommonCrypto/RC4CommonCrypto.cs
+CommonCrypto/MD2Managed.g.cs
+CommonCrypto/MD4Managed.g.cs
+System/Environment.iOS.cs
+System/Guid.MonoTouch.cs
+System/NotSupportedException.iOS.cs
+CoreFoundation/CFHelpers.cs
+System.Security.Cryptography.X509Certificates/X509CertificateImplApple.cs
+System.Security.Cryptography.X509Certificates/X509Helper.Apple.cs
+System.Text/EncodingHelper.MonoTouch.cs
+++ /dev/null
-#include monotouch_opt_corlib.dll.sources
--- /dev/null
+#include monotouch_corlib.dll.exclude.sources
+++ /dev/null
-#include monotouch_opt_corlib.dll.sources
--- /dev/null
+#include monotouch_corlib.dll.exclude.sources
#include corlib.dll.sources
+CommonCrypto/CommonCrypto.cs
+CommonCrypto/CryptorTransform.cs
+CommonCrypto/FastCryptorTransform.cs
+CommonCrypto/CorlibExtras.cs
+CommonCrypto/MD5CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1Managed.g.cs
+CommonCrypto/SHA256Managed.g.cs
+CommonCrypto/SHA384Managed.g.cs
+CommonCrypto/SHA512Managed.g.cs
+CommonCrypto/TripleDESCryptoServiceProvider.g.cs
+CommonCrypto/DESCryptoServiceProvider.g.cs
+CommonCrypto/RC2CryptoServiceProvider.g.cs
+CommonCrypto/RijndaelManaged.cs
+CommonCrypto/SecRandom.cs
+CommonCrypto/RC4CommonCrypto.cs
+CommonCrypto/MD2Managed.g.cs
+CommonCrypto/MD4Managed.g.cs
+System/Environment.iOS.cs
+System/Guid.MonoTouch.cs
+System/NotSupportedException.iOS.cs
+CoreFoundation/CFHelpers.cs
+System.Security.Cryptography.X509Certificates/X509CertificateImplApple.cs
+System.Security.Cryptography.X509Certificates/X509Helper.Apple.cs
+System.Text/EncodingHelper.MonoTouch.cs
+++ /dev/null
-#include monotouch_opt_corlib.dll.sources
--- /dev/null
+#include monotouch_corlib.dll.exclude.sources
+++ /dev/null
-#include monotouch_opt_corlib.dll.sources
--- /dev/null
+System.Security.Cryptography/MD5CryptoServiceProvider.cs
+System.Security.Cryptography/SHA1CryptoServiceProvider.cs
+System.Security.Cryptography/SHA1CryptoServiceProvider.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/descryptoserviceprovider.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/rc2cryptoserviceprovider.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/rijndaelmanaged.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/sha1managed.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/sha256managed.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/sha384managed.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/sha512managed.cs
+../../../external/referencesource/mscorlib/system/security/cryptography/tripledescryptoserviceprovider.cs
+../Mono.Security/Mono.Security.Cryptography/ARC4Managed.cs
+../Mono.Security/Mono.Security.Cryptography/MD2Managed.cs
+../Mono.Security/Mono.Security.Cryptography/MD4Managed.cs
#include corlib.dll.sources
+CommonCrypto/CommonCrypto.cs
+CommonCrypto/CryptorTransform.cs
+CommonCrypto/FastCryptorTransform.cs
+CommonCrypto/CorlibExtras.cs
+CommonCrypto/MD5CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1CryptoServiceProvider.g.cs
+CommonCrypto/SHA1Managed.g.cs
+CommonCrypto/SHA256Managed.g.cs
+CommonCrypto/SHA384Managed.g.cs
+CommonCrypto/SHA512Managed.g.cs
+CommonCrypto/TripleDESCryptoServiceProvider.g.cs
+CommonCrypto/DESCryptoServiceProvider.g.cs
+CommonCrypto/RC2CryptoServiceProvider.g.cs
+CommonCrypto/RijndaelManaged.cs
+CommonCrypto/RC4CommonCrypto.cs
+CommonCrypto/MD2Managed.g.cs
+CommonCrypto/MD4Managed.g.cs
+CoreFoundation/CFHelpers.cs
+System.Security.Cryptography.X509Certificates/X509CertificateImplApple.cs
+System.Security.Cryptography.X509Certificates/X509Helper.Apple.cs
+++ /dev/null
-System.Security.Cryptography.X509Certificates/X509Helper.MonoTouch.opt.cs
return IsLeftResolvedExpressionValid (dmb.Arguments [0].Expr);
}
- if (expr is ConstantExpr || expr is TypeExpr || expr is NamespaceExpression || expr is This)
+ if (expr is ConstantExpr || expr is TypeExpr || expr is NamespaceExpression || expr is VariableReference)
return true;
return false;
return ParseResult.Success;
// csc options that we don't support
- case "/utf8output":
- case "/subsystemversion":
+ case "/analyzer":
+ case "/appconfig":
+ case "/baseaddress":
+ case "/deterministic":
+ case "/errorendlocation":
+ case "/errorlog":
+ case "/features":
case "/highentropyva":
case "/highentropyva+":
case "/highentropyva-":
- case "/win32manifest":
+ case "/link":
+ case "/moduleassemblyname":
case "/nowin32manifest":
+ case "/pathmap":
+ case "/pdb":
+ case "/preferreduilang":
+ case "/publicsign":
+ case "/reportanalyzer":
+ case "/ruleset":
+ case "/sqmsessionguid":
+ case "/subsystemversion":
+ case "/utf8output":
+ case "/win32manifest":
return ParseResult.Success;
default:
public static event Action Act = null;
public static dynamic BBB = null;
+ void ParameterTest (Person ParPerson)
+ {
+ Console.WriteLine (nameof (ParPerson.MyCar.Year));
+ }
+
public static int Main ()
{
string name;
if (name != "ToString")
return 7;
+ Person LocPerson = null;
+ name = nameof (LocPerson.MyCar.Year);
+ if (name != "Year")
+ return 8;
+
return 0;
}
}
<size>40</size>
</method>
<method name="Int32 Main()" attrs="150">
- <size>213</size>
+ <size>244</size>
</method>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
<size>7</size>
</method>
</type>
+ <type name="MainClass">
+ <method name="Void ParameterTest(Person)" attrs="129">
+ <size>12</size>
+ </method>
+ </type>
</test>
<test name="test-null-operator-01.cs">
<type name="S">
PROGRAM = cil-stringreplacer.exe
NO_INSTALL = yes
-LOCAL_MCS_FLAGS = -r:System.dll
+LOCAL_MCS_FLAGS = -r:System.dll -r:Mono.Cecil.dll
include ../../build/executable.make
static void RewriteAssembly (string assemblyLocation, Dictionary<string, string> resourcesStrings, CmdOptions options)
{
- var assembly = AssemblyDefinition.ReadAssembly (assemblyLocation);
+ var readerParameters = new ReaderParameters { ReadSymbols = true };
+ var assembly = AssemblyDefinition.ReadAssembly (assemblyLocation, readerParameters);
foreach (var module in assembly.Modules) {
foreach (var type in module.GetTypes ()) {
foreach (var method in type.Methods) {
}
}
- assembly.Write (assemblyLocation);
+ var writerParameters = new WriterParameters { WriteSymbols = true };
+ assembly.Write (assemblyLocation, writerParameters);
}
static bool LoadGetResourceStrings (Dictionary<string, string> resourcesStrings, CmdOptions options)
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <PropertyGroup>\r
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>\r
+ <ProjectGuid>{7A08A2B6-5AC3-4268-8566-B07648B50D01}</ProjectGuid>\r
+ <OutputType>Exe</OutputType>\r
+ <RootNamespace>cilstringreplacer</RootNamespace>\r
+ <AssemblyName>cilstringreplacer</AssemblyName>\r
+ <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">\r
+ <DebugSymbols>true</DebugSymbols>\r
+ <DebugType>full</DebugType>\r
+ <Optimize>false</Optimize>\r
+ <OutputPath>bin\Debug</OutputPath>\r
+ <DefineConstants>DEBUG;</DefineConstants>\r
+ <ErrorReport>prompt</ErrorReport>\r
+ <WarningLevel>4</WarningLevel>\r
+ <ExternalConsole>false</ExternalConsole>\r
+ <PlatformTarget>x86</PlatformTarget>\r
+ <Commandlineparameters>--resourcestrings:/Users/marek/git/mono/external/referencesource/mscorlib/mscorlib.txt /Users/marek/git/mono/mcs/class/lib/net_4_x/mscorlib.dll</Commandlineparameters>\r
+ <ConsolePause>false</ConsolePause>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">\r
+ <Optimize>true</Optimize>\r
+ <OutputPath>bin\Release</OutputPath>\r
+ <ErrorReport>prompt</ErrorReport>\r
+ <WarningLevel>4</WarningLevel>\r
+ <ExternalConsole>true</ExternalConsole>\r
+ <PlatformTarget>x86</PlatformTarget>\r
+ </PropertyGroup>\r
+ <ItemGroup>\r
+ <Reference Include="System" />\r
+ <Reference Include="Mono.Cecil">\r
+ <HintPath>..\..\class\lib\net_4_x\Mono.Cecil.dll</HintPath>\r
+ </Reference>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <Compile Include="cil-stringreplacer.cs">\r
+ <Link>cil-stringreplacer.cs</Link>\r
+ </Compile>\r
+ <Compile Include="..\..\class\Mono.Options\Mono.Options\Options.cs">\r
+ <Link>Options.cs</Link>\r
+ </Compile>\r
+ </ItemGroup>\r
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />\r
+</Project>
\ No newline at end of file
cil-stringreplacer.cs
../../class/Mono.Options/Mono.Options/Options.cs
-../../../external/cecil/Mono.Cecil/*.cs
-../../../external/cecil/Mono.Cecil.Cil/*.cs
-../../../external/cecil/Mono.Cecil.Metadata/*.cs
-../../../external/cecil/Mono.Cecil.PE/*.cs
-../../../external/cecil/Mono.Collections.Generic/*.cs
-../../../external/cecil/Mono/Empty.cs
-../../../external/cecil/Mono.Security.Cryptography/*.cs
SUBDIRS =
include ../../build/rules.make
-ALL_PROGRAMS = mono-api-info.exe
-
-COMMON_SOURCES = \
- AssemblyResolver.cs \
- Util.cs \
- WellFormedXmlWriter.cs
+ALL_PROGRAMS = mono-api-info.exe mono-api-html.exe
PROGRAM_INSTALL_DIR = $(mono_libdir)/mono/$(FRAMEWORK_VERSION)
APIINFO_SOURCES = \
mono-api-info.cs \
- ../../class/Mono.Options/Mono.Options/Options.cs \
- $(COMMON_SOURCES)
+ AssemblyResolver.cs \
+ Util.cs \
+ WellFormedXmlWriter.cs \
+ ../../class/Mono.Options/Mono.Options/Options.cs
+
+APIHTML_SOURCES = \
+ mono-api-html/ApiChange.cs \
+ mono-api-html/ApiDiff.cs \
+ mono-api-html/AssemblyComparer.cs \
+ mono-api-html/ClassComparer.cs \
+ mono-api-html/Comparer.cs \
+ mono-api-html/ConstructorComparer.cs \
+ mono-api-html/EventComparer.cs \
+ mono-api-html/FieldComparer.cs \
+ mono-api-html/Helpers.cs \
+ mono-api-html/InterfaceComparer.cs \
+ mono-api-html/MemberComparer.cs \
+ mono-api-html/MethodComparer.cs \
+ mono-api-html/NamespaceComparer.cs \
+ mono-api-html/PropertyComparer.cs \
+ ../../class/Mono.Options/Mono.Options/Options.cs
-DISTFILES= $(COMMON_SOURCES) $(APIINFO_SOURCES)
+
+DISTFILES= $(APIINFO_SOURCES) $(APIHTML_SOURCES)
all-local: $(ALL_PROGRAMS)
dist-local: dist-default
-mono-api-info.exe: $(APIINFO_SOURCES) ../../class/Mono.Options/Mono.Options/Options.cs
+mono-api-info.exe: $(APIINFO_SOURCES)
$(CSCOMPILE) -r:Mono.Cecil.dll -r:System.Xml.dll -r:System.Core.dll -r:System.dll -out:$@ $^
+
+mono-api-html.exe: $(APIHTML_SOURCES)
+ $(CSCOMPILE) -r:Mono.Cecil.dll -r:System.Xml.dll -r:System.Core.dll -r:System.dll -r:System.Xml.Linq.dll -out:$@ $^
Copy (name, asmb_path, true);
+ var name_pdb = Path.ChangeExtension (name, ".pdb");
+ if (File.Exists (name_pdb)) {
+ Copy (name_pdb, Path.ChangeExtension (asmb_path, ".pdb"), true);
+ }
+
foreach (string ext in siblings) {
string sibling = String.Concat (name, ext);
if (File.Exists (sibling))
string pkg_path = AbsoluteToRelativePath (ref_dir, pkg_path_abs);
symlink (pkg_path, ref_path);
+ var pdb_pkg_path = Path.ChangeExtension (pkg_path, ".pdb");
+ var pdb_ref_path = Path.ChangeExtension (ref_path, ".pdb");
+
+ if (File.Exists (pdb_pkg_path)) {
+ symlink (pdb_pkg_path, pdb_ref_path);
+ } else {
+ try {
+ File.Delete (pdb_ref_path);
+ } catch {
+ // Ignore error, just delete files that should not be there.
+ }
+ }
+
foreach (string ext in siblings) {
string sibling = String.Concat (pkg_path, ext);
string sref = String.Concat (ref_path, ext);
+
if (File.Exists (sibling))
symlink (sibling, sref);
else {
break;
case "--static":
static_link = true;
- if (!quiet) {
- Console.WriteLine ("Note that statically linking the LGPL Mono runtime has more licensing restrictions than dynamically linking.");
- Console.WriteLine ("See http://www.mono-project.com/Licensing for details on licensing.");
- }
break;
case "--config":
if (i+1 == top) {
using System.Collections.Generic;
using Mono.Cecil;
using Mono.CompilerServices.SymbolWriter;
+using System.Runtime.InteropServices;
namespace Symbolicate
{
return true;
}
- static MethodInfo methodGetIL;
+ SeqPointInfo seqPointInfo;
private int GetILOffsetFromFile (int methodToken, uint methodIndex, int nativeOffset)
{
- if (string.IsNullOrEmpty (seqPointDataPath))
- return -1;
+ if (seqPointInfo == null)
+ seqPointInfo = SeqPointInfo.Read (seqPointDataPath);
- if (methodGetIL == null)
- methodGetIL = typeof (StackFrame).GetMethod ("GetILOffsetFromFile", BindingFlags.NonPublic | BindingFlags.Static);
-
- if (methodGetIL == null)
- throw new Exception ("System.Diagnostics.StackFrame.GetILOffsetFromFile could not be found, make sure you have an updated mono installed.");
-
- return (int) methodGetIL.Invoke (null, new object[] {seqPointDataPath, methodToken, methodIndex, nativeOffset});
+ return seqPointInfo.GetILOffset (methodToken, methodIndex, nativeOffset);
}
- static MethodInfo methodGetMethodFullName;
private string GetMethodFullName (MethodBase m)
{
-
- if (methodGetMethodFullName == null)
- methodGetMethodFullName = typeof (StackTrace).GetMethod ("GetFullNameForStackTrace", BindingFlags.NonPublic | BindingFlags.Static);
-
- if (methodGetMethodFullName == null)
- throw new Exception ("System.Exception.GetFullNameForStackTrace could not be found, make sure you have an updated mono installed.");
-
StringBuilder sb = new StringBuilder ();
- methodGetMethodFullName.Invoke (null, new object[] {sb, m});
+
+ StackTraceHelper.GetFullNameForStackTrace (sb, m);
return sb.ToString ();
}
if (!File.Exists (assemblyPath))
throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
- var assembly = Assembly.LoadFrom (assemblyPath);
+ var assembly = Assembly.ReflectionOnlyLoadFrom (assemblyPath);
MonoSymbolFile symbolFile = null;
var symbolPath = assemblyPath + ".mdb";
--- /dev/null
+using System;
+using System.IO;
+using System.Collections.Generic;
+
+namespace Symbolicate
+{
+ static class BinaryReaderExtensions
+ {
+ public static int ReadVariableInt (this BinaryReader reader)
+ {
+ int val = 0;
+ for (var i = 0; i < 4; i++) {
+ var b = reader.ReadByte ();
+ val |= (b & 0x7f) << (7 * i);
+ if ((b & 0x80) == 0)
+ return val;
+ }
+
+ throw new Exception ("Invalid variable int");
+ }
+
+ public static int ReadVariableZigZagInt (this BinaryReader reader)
+ {
+ int enc = ReadVariableInt (reader);
+ int val = enc >> 1;
+ return ((enc & 1) == 0)? val : -val;
+ }
+ }
+
+ class SeqPointInfo
+ {
+ class MethodData
+ {
+ List<SeqPoint> seqPoints;
+
+ public static MethodData Read (BinaryReader reader)
+ {
+ var hasDebugData = reader.ReadVariableInt () != 0;
+ var dataSize = reader.ReadVariableInt ();
+ var dataEnd = reader.BaseStream.Position + dataSize;
+
+ var seqPoints = new List<SeqPoint> ();
+ SeqPoint prev = null;
+ while (reader.BaseStream.Position < dataEnd) {
+ var seqPoint = SeqPoint.Read (reader, prev, hasDebugData);
+ seqPoints.Add (seqPoint);
+ prev = seqPoint;
+ }
+
+ if (reader.BaseStream.Position != dataEnd)
+ throw new Exception ("Read more seq point than expected.");
+
+ return new MethodData () { seqPoints = seqPoints };
+ }
+
+ public bool TryGetILOffset (int nativeOffset, out int ilOffset)
+ {
+ ilOffset = 0;
+ SeqPoint prev = null;
+ foreach (var seqPoint in seqPoints) {
+ if (seqPoint.NativeOffset > nativeOffset)
+ break;
+ prev = seqPoint;
+ }
+
+ if (prev == null)
+ return false;
+
+ ilOffset = prev.ILOffset;
+ return true;
+ }
+ }
+
+ class SeqPoint
+ {
+ public readonly int ILOffset;
+ public readonly int NativeOffset;
+
+ public SeqPoint (int ilOffset, int nativeOffset)
+ {
+ ILOffset = ilOffset;
+ NativeOffset = nativeOffset;
+ }
+
+ public static SeqPoint Read (BinaryReader reader, SeqPoint prev, bool hasDebug)
+ {
+ var ilOffset = reader.ReadVariableZigZagInt ();
+ var nativeOffset = reader.ReadVariableZigZagInt ();
+
+ // Respect delta encoding
+ if (prev != null) {
+ ilOffset += prev.ILOffset;
+ nativeOffset += prev.NativeOffset;
+ }
+
+ //Read everything to ensure the buffer position is at the end of the seq point data.
+ if (hasDebug) {
+ reader.ReadVariableInt (); // flags
+
+ var next_length = reader.ReadVariableInt ();
+ for (var i = 0; i < next_length; ++i)
+ reader.ReadVariableInt ();
+ }
+
+ return new SeqPoint (ilOffset, nativeOffset);
+ }
+ };
+
+ Dictionary<Tuple<int,int>, MethodData> dataByIds;
+ Dictionary<int, MethodData> dataByTokens;
+
+ public static SeqPointInfo Read (string path)
+ {
+ using (var reader = new BinaryReader (File.Open (path, FileMode.Open)))
+ {
+ var dataByIds = new Dictionary<Tuple<int,int>, MethodData> ();
+ var dataByTokens = new Dictionary<int, MethodData> ();
+
+ var methodCount = reader.ReadVariableInt ();
+
+ for (var i = 0; i < methodCount; ++i) {
+ var methodToken = reader.ReadVariableInt ();
+ var methodIndex = reader.ReadVariableInt ();
+ var methodId = new Tuple<int, int> (methodToken, methodIndex);
+
+ var methodData = MethodData.Read (reader);
+
+ dataByIds.Add (methodId, methodData);
+ if (!dataByTokens.ContainsKey (methodToken))
+ dataByTokens.Add (methodToken, methodData);
+ }
+
+ return new SeqPointInfo { dataByIds = dataByIds, dataByTokens = dataByTokens };
+ }
+ }
+
+ public int GetILOffset (int methodToken, uint methodIndex, int nativeOffset)
+ {
+ MethodData methodData;
+ if (methodIndex == 0xffffff) {
+ if (!dataByTokens.TryGetValue (methodToken, out methodData))
+ throw new Exception (string.Format ("Could not find data for method token {0:X}", methodToken));
+ } else {
+ var methodId = new Tuple<int, int> (methodToken, (int)methodIndex);
+ if (!dataByIds.TryGetValue (methodId, out methodData))
+ throw new Exception (string.Format ("Could not find data for method token {0:X} with index {1:X}", methodToken, methodIndex));
+ }
+
+ int ilOffset;
+ if (!methodData.TryGetILOffset (nativeOffset, out ilOffset))
+ throw new Exception ("Could not retrieve IL offset");
+
+ return ilOffset;
+ }
+ }
+}
symbolicate.cs
-LocationProvider.cs
\ No newline at end of file
+LocationProvider.cs
+SeqPointInfo.cs
+../../class/corlib/System.Diagnostics/StackTraceHelper.cs
*
* Copyright (C) 2000 Intel Corporation. All rights reserved.
* Copyright (C) 2001, 2002 Ximian, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef AMD64_H
* Copyright (c) 2002-2003 Sergey Chaban <serge@wildwestsoftware.com>
* Copyright 2005-2011 Novell Inc
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
//
// Copyright 2011 Xamarin Inc
//
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef __MONO_ARM_VFP_CODEGEN_H__
#define __MONO_ARM_VFP_CODEGEN_H__
* ARM CodeGen\r
* XScale WirelessMMX extensions\r
* Copyright 2002 Wild West Software\r
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.\r
*/\r
\r
#ifndef __WMMX_H__\r
-#include "../../../../mono-extensions/mono/arch/arm64/arm64-codegen.h"
+/*
+ * arm64-codegen.h: ARM64 code generation macros
+ *
+ * Author:
+ * Zoltan Varga (vargaz@gmail.com)
+ *
+ * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#ifndef __ARM64_CODEGEN_H__
+#define __ARM64_CODEGEN_H__
+#include <glib.h>
+
+enum {
+ ARMREG_R0 = 0,
+ ARMREG_R1 = 1,
+ ARMREG_R2 = 2,
+ ARMREG_R3 = 3,
+ ARMREG_R4 = 4,
+ ARMREG_R5 = 5,
+ ARMREG_R6 = 6,
+ ARMREG_R7 = 7,
+ ARMREG_R8 = 8,
+ ARMREG_R9 = 9,
+ ARMREG_R10 = 10,
+ ARMREG_R11 = 11,
+ ARMREG_R12 = 12,
+ ARMREG_R13 = 13,
+ ARMREG_R14 = 14,
+ ARMREG_R15 = 15,
+ ARMREG_R16 = 16,
+ ARMREG_R17 = 17,
+ ARMREG_R18 = 18,
+ ARMREG_R19 = 19,
+ ARMREG_R20 = 20,
+ ARMREG_R21 = 21,
+ ARMREG_R22 = 22,
+ ARMREG_R23 = 23,
+ ARMREG_R24 = 24,
+ ARMREG_R25 = 25,
+ ARMREG_R26 = 26,
+ ARMREG_R27 = 27,
+ ARMREG_R28 = 28,
+ ARMREG_R29 = 29,
+ ARMREG_R30 = 30,
+ ARMREG_SP = 31,
+ ARMREG_RZR = 31,
+
+ ARMREG_IP0 = ARMREG_R16,
+ ARMREG_IP1 = ARMREG_R17,
+ ARMREG_FP = ARMREG_R29,
+ ARMREG_LR = ARMREG_R30
+};
+
+enum {
+ ARMREG_D0 = 0,
+ ARMREG_D1 = 1,
+ ARMREG_D2 = 2,
+ ARMREG_D3 = 3,
+ ARMREG_D4 = 4,
+ ARMREG_D5 = 5,
+ ARMREG_D6 = 6,
+ ARMREG_D7 = 7,
+ ARMREG_D8 = 8,
+ ARMREG_D9 = 9,
+ ARMREG_D10 = 10,
+ ARMREG_D11 = 11,
+ ARMREG_D12 = 12,
+ ARMREG_D13 = 13,
+ ARMREG_D14 = 14,
+ ARMREG_D15 = 15,
+ ARMREG_D16 = 16,
+ ARMREG_D17 = 17,
+ ARMREG_D18 = 18,
+ ARMREG_D19 = 19,
+ ARMREG_D20 = 20,
+ ARMREG_D21 = 21,
+ ARMREG_D22 = 22,
+ ARMREG_D23 = 23,
+ ARMREG_D24 = 24,
+ ARMREG_D25 = 25,
+ ARMREG_D26 = 26,
+ ARMREG_D27 = 27,
+ ARMREG_D28 = 28,
+ ARMREG_D29 = 29,
+ ARMREG_D30 = 30,
+ ARMREG_D31 = 31
+};
+
+typedef enum {
+ ARMCOND_EQ = 0x0, /* Equal; Z = 1 */
+ ARMCOND_NE = 0x1, /* Not equal, or unordered; Z = 0 */
+ ARMCOND_CS = 0x2, /* Carry set; C = 1 */
+ ARMCOND_HS = ARMCOND_CS, /* Unsigned higher or same; */
+ ARMCOND_CC = 0x3, /* Carry clear; C = 0 */
+ ARMCOND_LO = ARMCOND_CC, /* Unsigned lower */
+ ARMCOND_MI = 0x4, /* Negative; N = 1 */
+ ARMCOND_PL = 0x5, /* Positive or zero; N = 0 */
+ ARMCOND_VS = 0x6, /* Overflow; V = 1 */
+ ARMCOND_VC = 0x7, /* No overflow; V = 0 */
+ ARMCOND_HI = 0x8, /* Unsigned higher; C = 1 && Z = 0 */
+ ARMCOND_LS = 0x9, /* Unsigned lower or same; C = 0 || Z = 1 */
+ ARMCOND_GE = 0xA, /* Signed greater than or equal; N = V */
+ ARMCOND_LT = 0xB, /* Signed less than; N != V */
+ ARMCOND_GT = 0xC, /* Signed greater than; Z = 0 && N = V */
+ ARMCOND_LE = 0xD, /* Signed less than or equal; Z = 1 || N != V */
+ ARMCOND_AL = 0xE, /* Always */
+ ARMCOND_NV = 0xF, /* Never */
+} ARMCond;
+
+typedef enum {
+ ARMSHIFT_LSL = 0x0,
+ ARMSHIFT_LSR = 0x1,
+ ARMSHIFT_ASR = 0x2
+} ARMShift;
+
+typedef enum {
+ ARMSIZE_B = 0x0,
+ ARMSIZE_H = 0x1,
+ ARMSIZE_W = 0x2,
+ ARMSIZE_X = 0x3
+} ARMSize;
+
+#define arm_emit(p, ins) do { *(guint32*)(p) = (ins); (p) += 4; } while (0)
+
+/* Overwrite bits [offset,offset+nbits] with value */
+static G_GNUC_UNUSED inline void
+arm_set_ins_bits (void *p, int offset, int nbits, guint32 value)
+{
+ *(guint32*)p = (*(guint32*)p & ~(((1 << nbits) - 1) << offset)) | (value << offset);
+}
+
+/*
+ * Naming conventions for codegen macros:
+ * - 64 bit opcodes have an 'X' suffix
+ * - 32 bit opcodes have a 'W' suffix
+ * - the order of operands is the same as in assembly
+ */
+
+/*
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0487a/index.html
+ */
+
+/* Uncoditional branch (register) */
+
+// 0b1101011 == 0x6b
+#define arm_format_breg(p, opc, op2, op3, op4, rn) arm_emit ((p), (0x6b << 25) | ((opc) << 21) | ((op2) << 16) | ((op3) << 10) | ((rn) << 5) | ((op4) << 0))
+
+// 0b0000 == 0x0, 0b11111 == 0x1f
+#define arm_brx(p, reg) arm_format_breg ((p), 0x0, 0x1f, 0x0, 0x0, (reg))
+
+// 0b0001 == 0x1
+#define arm_blrx(p, reg) arm_format_breg ((p), 0x1, 0x1f, 0x0, 0x0, (reg))
+
+//0b0010 == 0x2
+#define arm_retx(p, reg) arm_format_breg ((p), 0x2, 0x1f, 0x0, 0x0, (reg))
+
+/* Unconditional branch (immeditate) */
+
+static G_GNUC_UNUSED inline gboolean
+arm_is_bl_disp (void *code, void *target)
+{
+ gint64 disp = ((char*)(target) - (char*)(code)) / 4;
+
+ return (disp > -(1 << 25)) && (disp < (1 << 25));
+}
+
+static G_GNUC_UNUSED inline unsigned int
+arm_get_disp (void *p, void *target)
+{
+ unsigned int disp = ((char*)target - (char*)p) / 4;
+
+ if (target)
+ g_assert (arm_is_bl_disp (p, target));
+
+ return (disp & 0x3ffffff);
+}
+
+// 0b00101 == 0x5
+#define arm_b(p, target) arm_emit (p, (0x0 << 31) | (0x5 << 26) | ((arm_get_disp ((p), (target)) << 0)))
+
+#define arm_bl(p, target) arm_emit (p, (0x1 << 31) | (0x5 << 26) | ((arm_get_disp ((p), (target)) << 0)))
+
+/* Conditional branch */
+
+static G_GNUC_UNUSED inline gboolean
+arm_is_disp19 (void *code, void *target)
+{
+ gint64 disp = ((char*)(target) - (char*)(code)) / 4;
+
+ return (disp > -(1 << 18)) && (disp < (1 << 18));
+}
+
+static G_GNUC_UNUSED inline unsigned int
+arm_get_disp19 (void *p, void *target)
+{
+ unsigned int disp = ((char*)target - (char*)p) / 4;
+
+ if (target)
+ g_assert (arm_is_disp19 (p, target));
+
+ return (disp & 0x7ffff);
+}
+
+// 0b0101010 == 0x2a
+#define arm_format_condbr(p, o1, o0, cond, disp) arm_emit ((p), (0x2a << 25) | ((o1) << 24) | ((disp) << 5) | ((o0) << 4) | ((cond) << 0))
+#define arm_get_bcc_cond(p) ((*(guint32*)p) & 0xf)
+
+#define arm_bcc(p, cond, target) arm_format_condbr ((p), 0x0, 0x0, (cond), arm_get_disp19 ((p), (target)))
+
+// 0b011010 == 0x1a
+#define arm_format_cmpbr(p, sf, op, rt, target) arm_emit ((p), ((sf) << 31) | (0x1a << 25) | ((op) << 24) | (arm_get_disp19 ((p), (target)) << 5) | ((rt) << 0))
+
+#define arm_set_cbz_target(p, target) arm_set_ins_bits (p, 5, 19, arm_get_disp19 ((p), (target)))
+
+#define arm_cbzx(p, rt, target) arm_format_cmpbr ((p), 0x1, 0x0, (rt), (target))
+#define arm_cbzw(p, rt, target) arm_format_cmpbr ((p), 0x0, 0x0, (rt), (target))
+
+#define arm_cbnzx(p, rt, target) arm_format_cmpbr ((p), 0x1, 0x1, (rt), (target))
+#define arm_cbnzw(p, rt, target) arm_format_cmpbr ((p), 0x0, 0x1, (rt), (target))
+
+static G_GNUC_UNUSED inline unsigned int
+arm_get_disp15 (void *p, void *target)
+{
+ unsigned int disp = ((char*)target - (char*)p) / 4;
+ return (disp & 0x7fff);
+}
+
+// 0b011011 == 0x1b
+#define arm_format_tbimm(p, op, rt, bit, target) arm_emit ((p), ((((bit) >> 5) & 1) << 31) | (0x1b << 25) | ((op) << 24) | (((bit) & 0x1f) << 19) | (arm_get_disp15 ((p), (target)) << 5) | ((rt) << 0))
+
+#define arm_tbz(p, rt, bit, target) arm_format_tbimm ((p), 0x0, (rt), (bit), (target))
+#define arm_tbnz(p, rt, bit, target) arm_format_tbimm ((p), 0x1, (rt), (bit), (target))
+
+/* Memory access */
+
+#define arm_is_pimm12_scaled(pimm,size) ((pimm) >= 0 && (pimm) / (size) <= 0xfff && ((pimm) % (size)) == 0)
+
+static G_GNUC_UNUSED unsigned int
+arm_encode_pimm12 (int pimm, int size)
+{
+ g_assert (arm_is_pimm12_scaled (pimm, size));
+ return ((unsigned int)(pimm / size)) & 0xfff;
+}
+
+#define arm_is_strb_imm(pimm) arm_is_pimm12_scaled((pimm), 1)
+#define arm_is_strh_imm(pimm) arm_is_pimm12_scaled((pimm), 2)
+#define arm_is_strw_imm(pimm) arm_is_pimm12_scaled((pimm), 4)
+#define arm_is_strx_imm(pimm) arm_is_pimm12_scaled((pimm), 8)
+
+/* Load/Store register + scaled immediate */
+/* No pre-index/post-index yet */
+#define arm_format_mem_imm(p, size, opc, rt, rn, pimm, scale) arm_emit ((p), ((size) << 30) | (0x39 << 24) | ((opc) << 22) | (arm_encode_pimm12 ((pimm), (scale)) << 10) | ((rn) << 5) | ((rt) << 0))
+
+/* C5.6.83 LDR (immediate) */
+#define arm_ldrx(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_X, 0x1, (rt), (rn), (pimm), 8)
+#define arm_ldrw(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_W, 0x1, (rt), (rn), (pimm), 4)
+/* C5.6.86 LDRB (immediate) */
+#define arm_ldrb(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_B, 0x1, (rt), (rn), (pimm), 1)
+/* C5.6.88 LDRH (immediate) */
+#define arm_ldrh(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_H, 0x1, (rt), (rn), (pimm), 2)
+/* C5.6.90 LDRSB (immediate) */
+#define arm_ldrsbx(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_B, 0x2, (rt), (rn), (pimm), 1)
+#define arm_ldrsbw(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_B, 0x3, (rt), (rn), (pimm), 1)
+/* C5.6.92 LDRSH (immediate) */
+#define arm_ldrshx(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_H, 0x2, (rt), (rn), (pimm), 2)
+#define arm_ldrshw(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_H, 0x3, (rt), (rn), (pimm), 2)
+/* C5.6.94 LDRSW (immediate) */
+#define arm_ldrswx(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_W, 0x2, (rt), (rn), (pimm), 4)
+
+/* C5.6.178 STR (immediate) */
+#define arm_strx(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_X, 0x0, (rt), (rn), (pimm), 8)
+#define arm_strw(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_W, 0x0, (rt), (rn), (pimm), 4)
+/* C5.6.182 STR (immediate) */
+#define arm_strh(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_H, 0x0, (rt), (rn), (pimm), 2)
+#define arm_strb(p, rt, rn, pimm) arm_format_mem_imm (p, ARMSIZE_B, 0x0, (rt), (rn), (pimm), 1)
+
+/* C3.3.9 Load/store register (immediate post-indexed) */
+static G_GNUC_UNUSED unsigned int
+arm_encode_simm9 (int simm)
+{
+ g_assert (simm >= -256 && simm <= 255);
+ return ((unsigned int)simm) & 0x1ff;
+}
+
+#define arm_format_mem_imm_post(p, size, V, opc, rt, rn, simm) arm_emit ((p), ((size) << 30) | (0x7 << 27) | ((V) << 26) | (0x0 << 24) | ((opc) << 22) | (arm_encode_simm9 ((simm)) << 12) | (0x1 << 10) | ((rn) << 5) | ((rt) << 0))
+
+#define arm_ldrx_post(p, rt, rn, simm) arm_format_mem_imm_post (p, ARMSIZE_X, 0x0, 0x1, (rt), (rn), (simm))
+#define arm_ldrw_post(p, rt, rn, simm) arm_format_mem_imm_post (p, ARMSIZE_W, 0x0, 0x1, (rt), (rn), (simm))
+
+#define arm_strx_post(p, rt, rn, simm) arm_format_mem_imm_post (p, ARMSIZE_X, 0x0, 0x0, (rt), (rn), (simm))
+#define arm_strw_post(p, rt, rn, simm) arm_format_mem_imm_post (p, ARMSIZE_W, 0x0, 0x0, (rt), (rn), (simm))
+
+/* C3.3.9 Load/store register (immediate pre-indexed) */
+#define arm_format_mem_imm_pre(p, size, V, opc, rt, rn, simm) arm_emit ((p), ((size) << 30) | (0x7 << 27) | ((V) << 26) | (0x0 << 24) | ((opc) << 22) | (arm_encode_simm9 ((simm)) << 12) | (0x3 << 10) | ((rn) << 5) | ((rt) << 0))
+
+#define arm_ldrx_pre(p, rt, rn, simm) arm_format_mem_imm_pre (p, ARMSIZE_X, 0x0, 0x1, (rt), (rn), (simm))
+#define arm_ldrw_pre(p, rt, rn, simm) arm_format_mem_imm_pre (p, ARMSIZE_W, 0x0, 0x1, (rt), (rn), (simm))
+
+#define arm_strx_pre(p, rt, rn, simm) arm_format_mem_imm_pre (p, ARMSIZE_X, 0x0, 0x0, (rt), (rn), (simm))
+#define arm_strw_pre(p, rt, rn, simm) arm_format_mem_imm_pre (p, ARMSIZE_W, 0x0, 0x0, (rt), (rn), (simm))
+
+/* Load/Store register + register */
+/* No extend/scale yet */
+#define arm_format_mem_reg(p, size, opc, rt, rn, rm) arm_emit ((p), ((size) << 30) | (0x38 << 24) | ((opc) << 22) | (0x1 << 21) | ((rm) << 16) | (0x3 << 13) | (0 << 12) | (0x2 << 10) | ((rn) << 5) | ((rt) << 0))
+
+/* C5.6.85 LDR (register) */
+#define arm_ldrx_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_X, 0x1, (rt), (rn), (rm))
+#define arm_ldrw_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_W, 0x1, (rt), (rn), (rm))
+/* C5.6.87 LDRB (register) */
+#define arm_ldrb_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_B, 0x1, (rt), (rn), (rm))
+/* C5.6.88 LDRH (register) */
+#define arm_ldrh_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_H, 0x1, (rt), (rn), (rm))
+/* C5.6.91 LDRSB (register) */
+#define arm_ldrsbx_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_B, 0x2, (rt), (rn), (rm))
+#define arm_ldrsbw_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_B, 0x3, (rt), (rn), (rm))
+/* C5.6.93 LDRSH (register) */
+#define arm_ldrshx_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_H, 0x2, (rt), (rn), (rm))
+#define arm_ldrshw_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_H, 0x3, (rt), (rn), (rm))
+/* C5.6.96 LDRSW (register) */
+#define arm_ldrswx_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_W, 0x2, (rt), (rn), (rm))
+
+/* C5.6.179 STR (register) */
+#define arm_strx_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_X, 0x0, (rt), (rn), (rm))
+#define arm_strw_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_W, 0x0, (rt), (rn), (rm))
+/* C5.6.181 STRB (register) */
+#define arm_strb_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_B, 0x0, (rt), (rn), (rm))
+/* C5.6.183 STRH (register) */
+#define arm_strh_reg(p, rt, rn, rm) arm_format_mem_reg ((p), ARMSIZE_H, 0x0, (rt), (rn), (rm))
+
+/* PC relative */
+
+/* C5.6.84 LDR (literal) */
+
+#define arm_get_ldr_lit_reg(p) (*(guint32*)(p) & 0x1f)
+
+#define arm_ldrx_lit(p, rt, target) arm_emit ((p), (0x01 << 30) | (0x18 << 24) | (arm_get_disp19 ((p), (target)) << 5) | ((rt) << 0))
+#define arm_ldrw_lit(p, rt, target) arm_emit ((p), (0x00 << 30) | (0x18 << 24) | (arm_get_disp19 ((p), (target)) << 5) | ((rt) << 0))
+#define arm_ldrswx_lit(p, rt, target) arm_emit ((p), (0x2 << 30) | (0x18 << 24) | (arm_get_disp19 ((p), (target)) << 5) | ((rt) << 0))
+
+/* Unscaled offset */
+/* FIXME: Not yet */
+
+/* Load/Store Pair */
+
+static G_GNUC_UNUSED unsigned int
+arm_encode_imm7 (int imm, int size)
+{
+ g_assert (imm / size >= -64 && imm / size <= 63 && (imm % size) == 0);
+ return ((unsigned int)(imm / size)) & 0x7f;
+}
+
+#define arm_is_imm7_scaled(imm, size) ((imm) / (size) >= -64 && (imm) / (size) <= 63 && ((imm) % (size)) == 0)
+
+#define arm_is_ldpx_imm(imm) arm_is_imm7_scaled ((imm), 8)
+
+/* C3.3.14 */
+#define arm_format_mem_p(p, size, opc, L, rt1, rt2, rn, imm) arm_emit ((p), (opc << 30) | (0x52 << 23) | ((L) << 22) | (arm_encode_imm7 (imm, size) << 15) | ((rt2) << 10) | ((rn) << 5) | ((rt1) << 0))
+
+#define arm_ldpx(p, rt1, rt2, rn, imm) arm_format_mem_p ((p), 8, 0x2, 1, (rt1), (rt2), (rn), (imm))
+#define arm_ldpw(p, rt1, rt2, rn, imm) arm_format_mem_p ((p), 4, 0x0, 1, (rt1), (rt2), (rn), (imm))
+#define arm_ldpsw(p, rt1, rt2, rn, imm) arm_format_mem_p ((p), 4, 0x1, 1, (rt1), (rt2), (rn), (imm))
+#define arm_stpx(p, rt1, rt2, rn, imm) arm_format_mem_p ((p), 8, 0x2, 0, (rt1), (rt2), (rn), (imm))
+#define arm_stpw(p, rt1, rt2, rn, imm) arm_format_mem_p ((p), 4, 0x0, 0, (rt1), (rt2), (rn), (imm))
+
+/* Load/Store Pair (Pre-indexed) */
+/* C3.3.16 */
+#define arm_format_mem_p_pre(p, size, opc, L, rt1, rt2, rn, imm) arm_emit ((p), (opc << 30) | (0x53 << 23) | ((L) << 22) | (arm_encode_imm7 (imm, size) << 15) | ((rt2) << 10) | ((rn) << 5) | ((rt1) << 0))
+
+#define arm_ldpx_pre(p, rt1, rt2, rn, imm) arm_format_mem_p_pre ((p), 8, 0x2, 1, (rt1), (rt2), (rn), (imm))
+#define arm_ldpw_pre(p, rt1, rt2, rn, imm) arm_format_mem_p_pre ((p), 4, 0x0, 1, (rt1), (rt2), (rn), (imm))
+#define arm_ldpsw_pre(p, rt1, rt2, rn, imm) arm_format_mem_p_pre ((p), 4, 0x1, 1, (rt1), (rt2), (rn), (imm))
+#define arm_stpx_pre(p, rt1, rt2, rn, imm) arm_format_mem_p_pre ((p), 8, 0x2, 0, (rt1), (rt2), (rn), (imm))
+#define arm_stpw_pre(p, rt1, rt2, rn, imm) arm_format_mem_p_pre ((p), 4, 0x0, 0, (rt1), (rt2), (rn), (imm))
+
+/* Not an official alias */
+#define arm_pushpx (p, rt1, rt2) arm_LDPX_pre (p, rt1, rt2, ARMREG_RSP, -8)
+
+/* Load/Store Pair (Post-indexed) */
+/* C3.3.15 */
+#define arm_format_mem_p_post(p, size, opc, L, rt1, rt2, rn, imm) arm_emit ((p), (opc << 30) | (0x51 << 23) | ((L) << 22) | (arm_encode_imm7 (imm, size) << 15) | ((rt2) << 10) | ((rn) << 5) | ((rt1) << 0))
+
+#define arm_ldpx_post(p, rt1, rt2, rn, imm) arm_format_mem_p_post ((p), 8, 0x2, 1, (rt1), (rt2), (rn), (imm))
+#define arm_ldpw_post(p, rt1, rt2, rn, imm) arm_format_mem_p_post ((p), 4, 0x0, 1, (rt1), (rt2), (rn), (imm))
+#define arm_ldpsw_post(p, rt1, rt2, rn, imm) arm_format_mem_p_post ((p), 4, 0x1, 1, (rt1), (rt2), (rn), (imm))
+#define arm_stpx_post(p, rt1, rt2, rn, imm) arm_format_mem_p_post ((p), 8, 0x2, 0, (rt1), (rt2), (rn), (imm))
+#define arm_stpw_post(p, rt1, rt2, rn, imm) arm_format_mem_p_post ((p), 4, 0x0, 0, (rt1), (rt2), (rn), (imm))
+
+/* Not an official alias */
+#define arm_poppx (p, rt1, rt2) arm_ldpx_post (p, rt1, rt2, ARMREG_RSP, 8)
+
+/* Load/Store Exclusive */
+#define arm_format_ldxr(p, size, rt, rn) arm_emit ((p), ((size) << 30) | (0x8 << 24) | (0x0 << 23) | (0x1 << 22) | (0x0 << 21) | (0x1f << 16) | (0x0 << 15) | (0x1f << 10) | ((rn) << 5) | ((rt) << 0))
+#define arm_format_ldxp(p, size, rt1, rt2, rn) arm_emit ((p), ((size) << 30) | (0x8 << 24) | (0x0 << 23) | (0x1 << 22) | (0x1 << 21) | (0x1f << 16) | (0x0 << 15) | ((rt2) << 10)| ((rn) << 5) | ((rt1) << 0))
+#define arm_format_stxr(p, size, rs, rt, rn) arm_emit ((p), ((size) << 30) | (0x8 << 24) | (0x0 << 23) | (0x0 << 22) | (0x0 << 21) | ((rs) << 16) | (0x0 << 15) | (0x1f << 10) | ((rn) << 5) | ((rt) << 0))
+#define arm_format_stxp(p, size, rs, rt1, rt2, rn) arm_emit ((p), ((size) << 30) | (0x8 << 24) | (0x0 << 23) | (0x0 << 22) | (0x1 << 21) | ((rs) << 16) | (0x0 << 15) | ((rt2) << 10)| ((rn) << 5) | ((rt1) << 0))
+
+#define arm_ldxrx(p, rt, rn) arm_format_ldxr ((p), ARMSIZE_X, (rt), (rn))
+#define arm_ldxrw(p, rt, rn) arm_format_ldxr ((p), ARMSIZE_W, (rt), (rn))
+#define arm_ldxrh(p, rt, rn) arm_format_ldxr ((p), ARMSIZE_H, (rt), (rn))
+#define arm_ldxrb(p, rt, rn) arm_format_ldxr ((p), ARMSIZE_B, (rt), (rn))
+#define arm_ldxpx(p, rt1, rt2, rn) arm_format_ldxp ((p), ARMSIZE_X, (rt1), (rt2), (rn))
+#define arm_ldxpw(p, rt1, rt2, rn) arm_format_ldxp ((p), ARMSIZE_W, (rt1), (rt2), (rn))
+#define arm_stxrx(p, rs, rt, rn) arm_format_stxr ((p), ARMSIZE_X, (rs), (rt), (rn))
+#define arm_stxrw(p, rs, rt, rn) arm_format_stxr ((p), ARMSIZE_W, (rs), (rt), (rn))
+#define arm_stxrh(p, rs, rt, rn) arm_format_stxr ((p), ARMSIZE_H, (rs), (rt), (rn))
+#define arm_stxrb(p, rs, rt, rn) arm_format_stxr ((p), ARMSIZE_B, (rs), (rt), (rn))
+#define arm_stxpx(p, rs, rt1, rt2, rn) arm_format_stxp ((p), ARMSIZE_X, (rs), (rt1), (rt2), (rn))
+#define arm_stxpw(p, rs, rt1, rt2, rn) arm_format_stxp ((p), ARMSIZE_W, (rs), (rt1), (rt2), (rn))
+
+/* C5.6.73 LDAR: Load-Acquire Register */
+
+#define arm_format_ldar(p, size, rt, rn) arm_emit ((p), ((size) << 30) | (0x8 << 24) | (0x1 << 23) | (0x1 << 22) | (0x0 << 21) | (0x1f << 16) | (0x1 << 15) | (0x1f << 10) | ((rn) << 5) | ((rt) << 0))
+
+#define arm_ldarx(p, rt, rn) arm_format_ldar ((p), ARMSIZE_X, (rt), (rn))
+#define arm_ldarw(p, rt, rn) arm_format_ldar ((p), ARMSIZE_W, (rt), (rn))
+#define arm_ldarh(p, rt, rn) arm_format_ldar ((p), ARMSIZE_H, (rt), (rn))
+#define arm_ldarb(p, rt, rn) arm_format_ldar ((p), ARMSIZE_B, (rt), (rn))
+
+/* C5.6.169 STLR: Store-Release Register */
+
+#define arm_format_stlr(p, size, rt, rn) arm_emit ((p), ((size) << 30) | (0x8 << 24) | (0x1 << 23) | (0x0 << 22) | (0x0 << 21) | (0x1f << 16) | (0x1 << 15) | (0x1f << 10) | ((rn) << 5) | ((rt) << 0))
+
+#define arm_stlrx(p, rn, rt) arm_format_stlr ((p), ARMSIZE_X, (rt), (rn))
+#define arm_stlrw(p, rn, rt) arm_format_stlr ((p), ARMSIZE_W, (rt), (rn))
+#define arm_stlrh(p, rn, rt) arm_format_stlr ((p), ARMSIZE_H, (rt), (rn))
+#define arm_stlrb(p, rn, rt) arm_format_stlr ((p), ARMSIZE_B, (rt), (rn))
+
+/* C5.6.77 LDAXR */
+#define arm_format_ldaxr(p, size, rn, rt) arm_emit ((p), ((size) << 30) | (0x8 << 24) | (0x0 << 23) | (0x1 << 22) | (0x0 << 21) | (0x1f << 16) | (0x1 << 15) | (0x1f << 10) | ((rn) << 5) | ((rt) << 0))
+
+#define arm_ldaxrx(p, rt, rn) arm_format_ldaxr ((p), 0x3, (rn), (rt))
+#define arm_ldaxrw(p, rt, rn) arm_format_ldaxr ((p), 0x2, (rn), (rt))
+
+/* C5.6.173 STLXR */
+#define arm_format_stlxr(p, size, rs, rn, rt) arm_emit ((p), ((size) << 30) | (0x8 << 24) | (0x0 << 23) | (0x0 << 22) | (0x0 << 21) | ((rs) << 16) | (0x1 << 15) | (0x1f << 10) | ((rn) << 5) | ((rt) << 0))
+
+#define arm_stlxrx(p, rs, rt, rn) arm_format_stlxr ((p), 0x3, (rs), (rn), (rt))
+#define arm_stlxrw(p, rs, rt, rn) arm_format_stlxr ((p), 0x2, (rs), (rn), (rt))
+
+/* Load/Store SIMD&FP */
+
+/* C6.3.285 STR (immediate, SIMD&FP) */
+#define arm_format_strfp_imm(p, size, opc, rt, rn, pimm, scale) arm_emit ((p), ((size) << 30) | (0xf << 26) | (0x1 << 24) | ((opc) << 22) | (arm_encode_pimm12 ((pimm), (scale)) << 10) | ((rn) << 5) | ((rt) << 0))
+
+/* Store double */
+#define arm_strfpx(p, dt, xn, simm) arm_format_strfp_imm ((p), ARMSIZE_X, 0x0, (dt), (xn), (simm), 8)
+/* Store single */
+#define arm_strfpw(p, st, xn, simm) arm_format_strfp_imm ((p), ARMSIZE_W, 0x0, (st), (xn), (simm), 4)
+
+/* C6.3.166 LDR (immediate, SIMD&FP) */
+#define arm_format_ldrfp_imm(p, size, opc, rt, rn, pimm, scale) arm_emit ((p), ((size) << 30) | (0xf << 26) | (0x1 << 24) | ((opc) << 22) | (arm_encode_pimm12 ((pimm), (scale)) << 10) | ((rn) << 5) | ((rt) << 0))
+
+/* Load double */
+#define arm_ldrfpx(p, dt, xn, simm) arm_format_ldrfp_imm ((p), ARMSIZE_X, 0x1, dt, xn, simm, 8)
+/* Load single */
+#define arm_ldrfpw(p, dt, xn, simm) arm_format_ldrfp_imm ((p), ARMSIZE_W, 0x1, dt, xn, simm, 4)
+
+/* Arithmetic (immediate) */
+static G_GNUC_UNUSED inline guint32
+arm_encode_arith_imm (int imm, guint32 *shift)
+{
+ // FIXME:
+ g_assert ((imm >= 0) && (imm < 0xfff));
+ *shift = 0;
+ return (guint32)imm;
+}
+
+// FIXME:
+#define arm_is_arith_imm(imm) (((imm) >= 0) && ((imm) < 0xfff))
+
+#define arm_format_alu_imm(p, sf, op, S, rd, rn, imm) do { \
+ guint32 _imm12, _shift; \
+ _imm12 = arm_encode_arith_imm ((imm), &_shift); arm_emit ((p), ((sf) << 31) | ((op) << 30) | ((S) << 29) | (0x11 << 24) | ((_shift) << 22) | ((_imm12) << 10) | ((rn) << 5) | ((rd) << 0)); \
+} while (0)
+
+/* rd/rn can be SP for addx/subx */
+#define arm_addx_imm(p, rd, rn, imm) arm_format_alu_imm ((p), 0x1, 0x0, 0x0, (rd), (rn), (imm))
+#define arm_addw_imm(p, rd, rn, imm) arm_format_alu_imm ((p), 0x0, 0x0, 0x0, (rd), (rn), (imm))
+#define arm_addsx_imm(p, rd, rn, imm) arm_format_alu_imm ((p), 0x1, 0x0, 0x1, (rd), (rn), (imm))
+#define arm_addsw_imm(p, rd, rn, imm) arm_format_alu_imm ((p), 0x0, 0x0, 0x1, (rd), (rn), (imm))
+#define arm_subx_imm(p, rd, rn, imm) arm_format_alu_imm ((p), 0x1, 0x1, 0x0, (rd), (rn), (imm))
+#define arm_subw_imm(p, rd, rn, imm) arm_format_alu_imm ((p), 0x0, 0x1, 0x0, (rd), (rn), (imm))
+#define arm_subsx_imm(p, rd, rn, imm) arm_format_alu_imm ((p), 0x1, 0x1, 0x1, (rd), (rn), (imm))
+#define arm_subsw_imm(p, rd, rn, imm) arm_format_alu_imm ((p), 0x0, 0x1, 0x1, (rd), (rn), (imm))
+
+#define arm_cmpx_imm(p, rn, imm) arm_subsx_imm ((p), ARMREG_RZR, (rn), (imm))
+#define arm_cmpw_imm(p, rn, imm) arm_subsw_imm ((p), ARMREG_RZR, (rn), (imm))
+#define arm_cmnx_imm(p, rn, imm) arm_addsx_imm ((p), ARMREG_RZR, (rn), (imm))
+#define arm_cmnw_imm(p, rn, imm) arm_addsw_imm ((p), ARMREG_RZR, (rn), (imm))
+
+/* Logical (immediate) */
+
+// FIXME: imm
+#if 0
+#define arm_format_and(p, sf, opc, rd, rn, imm) arm_emit ((p), ((sf) << 31) | ((opc) << 29) | (0x24 << 23) | ((0) << 22) | ((imm) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_andx_imm(p, rd, rn, imm) arm_format_and ((p), 0x1, 0x0, (rd), (rn), (imm))
+#define arm_andw_imm(p, rd, rn, imm) arm_format_and ((p), 0x0, 0x0, (rd), (rn), (imm))
+#define arm_andsx_imm(p, rd, rn, imm) arm_format_and ((p), 0x1, 0x3, (rd), (rn), (imm))
+#define arm_andsw_imm(p, rd, rn, imm) arm_format_and ((p), 0x0, 0x3, (rd), (rn), (imm))
+#define arm_eorx_imm(p, rd, rn, imm) arm_format_and ((p), 0x1, 0x2, (rd), (rn), (imm))
+#define arm_eorw_imm(p, rd, rn, imm) arm_format_and ((p), 0x0, 0x2, (rd), (rn), (imm))
+#define arm_orrx_imm(p, rd, rn, imm) arm_format_and ((p), 0x1, 0x1, (rd), (rn), (imm))
+#define arm_orrw_imm(p, rd, rn, imm) arm_format_and ((p), 0x0, 0x1, (rd), (rn), (imm))
+
+#define arm_tstx_imm(p, rn, imm) arm_andsx_imm ((p), ARMREG_RZR, (rn), (imm))
+#define arm_tstw_imm(p, rn, imm) arm_andsw_imm ((p), ARMREG_RZR, (rn), (imm))
+#endif
+
+/* Move (wide immediate) */
+#define arm_format_mov(p, sf, opc, hw, rd, imm16) arm_emit ((p), ((sf) << 31) | ((opc) << 29) | (0x25 << 23) | ((hw) << 21) | (((guint32)(imm16) & 0xffff) << 5) | ((rd) << 0))
+
+#define arm_get_movzx_rd(p) ((*(guint32*)p) & 0x1f)
+
+#define arm_movzx(p, rd, imm, shift) do { g_assert ((shift) % 16 == 0); arm_format_mov ((p), 0x1, 0x2, (shift) / 16, (rd), (imm)); } while (0)
+#define arm_movzw(p, rd, imm, shift) do { g_assert ((shift) % 16 == 0); arm_format_mov ((p), 0x0, 0x2, (shift) / 16, (rd), (imm)); } while (0)
+#define arm_movnx(p, rd, imm, shift) do { g_assert ((shift) % 16 == 0); arm_format_mov ((p), 0x1, 0x0, (shift) / 16, (rd), (imm)); } while (0)
+#define arm_movnw(p, rd, imm, shift) do { g_assert ((shift) % 16 == 0); arm_format_mov ((p), 0x0, 0x0, (shift) / 16, (rd), (imm)); } while (0)
+#define arm_movkx(p, rd, imm, shift) do { g_assert ((shift) % 16 == 0); arm_format_mov ((p), 0x1, 0x3, (shift) / 16, (rd), (imm)); } while (0)
+#define arm_movkw(p, rd, imm, shift) do { g_assert ((shift) % 16 == 0); arm_format_mov ((p), 0x0, 0x3, (shift) / 16, (rd), (imm)); } while (0)
+
+/* PC-relative address calculation */
+#define arm_format_adrp(p, op, rd, target) do { guint64 imm1 = (guint64)(target); guint64 imm2 = (guint64)(p); int _imm = imm1 - imm2; arm_emit ((p), ((op) << 31) | (((_imm) & 0x3) << 29) | (0x10 << 24) | (((_imm >> 2) & 0x7ffff) << 5) | ((rd) << 0)); } while (0)
+
+#define arm_adrpx(p, rd, target) arm_format_adrp ((p), 0x1, (rd), (target))
+#define arm_adrx(p, rd, target) arm_format_adrp ((p), 0x0, (rd), (target))
+
+/* Bitfield move */
+#define arm_format_bfm(p, sf, opc, N, immr, imms, rn, rd) arm_emit ((p), ((sf) << 31) | ((opc) << 29) | (0x26 << 23) | ((N) << 22) | ((N) << 22) | ((immr) << 16) | ((imms) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_bfmx(p, rd, rn, immr, imms) arm_format_bfm ((p), 0x1, 0x1, 0x1, (immr), (imms), (rn), (rd))
+#define arm_bfmw(p, rd, rn, immr, imms) arm_format_bfm ((p), 0x0, 0x1, 0x0, (immr), (imms), (rn), (rd))
+#define arm_sbfmx(p, rd, rn, immr, imms) arm_format_bfm ((p), 0x1, 0x0, 0x1, (immr), (imms), (rn), (rd))
+#define arm_sbfmw(p, rd, rn, immr, imms) arm_format_bfm ((p), 0x0, 0x0, 0x0, (immr), (imms), (rn), (rd))
+#define arm_ubfmx(p, rd, rn, immr, imms) arm_format_bfm ((p), 0x1, 0x2, 0x1, (immr), (imms), (rn), (rd))
+#define arm_ubfmw(p, rd, rn, immr, imms) arm_format_bfm ((p), 0x0, 0x2, 0x0, (immr), (imms), (rn), (rd))
+
+/* Sign extend and Zero-extend */
+#define arm_sxtbx(p, rd, rn) arm_sbfmx ((p), (rd), (rn), 0, 7)
+#define arm_sxtbw(p, rd, rn) arm_sbfmw ((p), (rd), (rn), 0, 7)
+#define arm_sxthx(p, rd, rn) arm_sbfmx ((p), (rd), (rn), 0, 15)
+#define arm_sxthw(p, rd, rn) arm_sbfmw ((p), (rd), (rn), 0, 15)
+#define arm_sxtwx(p, rd, rn) arm_sbfmx ((p), (rd), (rn), 0, 31)
+#define arm_uxtbx(p, rd, rn) arm_ubfmx ((p), (rd), (rn), 0, 7)
+#define arm_uxtbw(p, rd, rn) arm_ubfmw ((p), (rd), (rn), 0, 7)
+#define arm_uxthx(p, rd, rn) arm_ubfmx ((p), (rd), (rn), 0, 15)
+#define arm_uxthw(p, rd, rn) arm_ubfmw ((p), (rd), (rn), 0, 15)
+
+/* Extract register */
+#define arm_format_extr(p, sf, N, rd, rn, rm, imms) arm_emit ((p), ((sf) << 31) | (0x27 << 23) | ((N) << 22) | (0x0 << 21) | ((rm) << 16) | ((imms) << 10) | ((rn) << 5) | ((rd) << 0))
+#define arm_extrx(p, rd, rn, rm, lsb) arm_format_extr ((p), 0x1, 0x1, (rd), (rn), (rm), (lsb))
+#define arm_extrw(p, rd, rn, rm, lsb) arm_format_extr ((p), 0x0, 0x0, (rd), (rn), (rm), (lsb))
+
+/* Shift (immediate) */
+#define arm_asrx(p, rd, rn, shift) arm_sbfmx ((p), (rd), (rn), (shift), 63)
+#define arm_asrw(p, rd, rn, shift) arm_sbfmw ((p), (rd), (rn), (shift), 31)
+#define arm_lslx(p, rd, rn, shift) arm_ubfmx ((p), (rd), (rn), 64 - ((shift) % 64), 63 - ((shift) % 64))
+#define arm_lslw(p, rd, rn, shift) arm_ubfmw ((p), (rd), (rn), 32 - ((shift) % 32), 31 - ((shift) % 32))
+#define arm_lsrx(p, rd, rn, shift) arm_ubfmx ((p), (rd), (rn), shift, 63)
+#define arm_lsrw(p, rd, rn, shift) arm_ubfmw ((p), (rd), (rn), shift, 31)
+#define arm_rorx(p, rd, rs, shift) arm_extrx ((p), (rd), (rs), (rs), (shift))
+#define arm_rorw(p, rd, rs, shift) arm_extrw ((p), (rd), (rs), (rs), (shift))
+
+/* Arithmetic (shifted register) */
+#define arm_format_alu_shift(p, sf, op, S, rd, rn, rm, shift, imm6) arm_emit ((p), ((sf) << 31) | ((op) << 30) | ((S) << 29) | (0xb << 24) | ((shift) << 22) | (0x0 << 21) | ((rm) << 16) | ((imm6) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_addx_shift(p, rd, rn, rm, shift_type, amount) arm_format_alu_shift ((p), 0x1, 0x0, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_addw_shift(p, rd, rn, rm, shift_type, amount) arm_format_alu_shift ((p), 0x0, 0x0, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_addsx_shift(p, rd, rn, rm, shift_type, amount) arm_format_alu_shift ((p), 0x1, 0x0, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_addsw_shift(p, rd, rn, rm, shift_type, amount) arm_format_alu_shift ((p), 0x0, 0x0, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_subx_shift(p, rd, rn, rm, shift_type, amount) arm_format_alu_shift ((p), 0x1, 0x1, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_subw_shift(p, rd, rn, rm, shift_type, amount) arm_format_alu_shift ((p), 0x0, 0x1, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_subsx_shift(p, rd, rn, rm, shift_type, amount) arm_format_alu_shift ((p), 0x1, 0x1, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_subsw_shift(p, rd, rn, rm, shift_type, amount) arm_format_alu_shift ((p), 0x0, 0x1, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_cmnx_shift(p, rn, rm, shift_type, amount) arm_addsx_shift ((p), ARMREG_RZR, (rn), (rm), (shift_type), (amount))
+#define arm_cmnw_shift(p, rn, rm, shift_type, amount) arm_addsw_shift ((p), ARMREG_RZR, (rn), (rm), (shift_type), (amount))
+#define arm_cmpx_shift(p, rn, rm, shift_type, amount) arm_subsx_shift ((p), ARMREG_RZR, (rn), (rm), (shift_type), (amount))
+#define arm_cmpw_shift(p, rn, rm, shift_type, amount) arm_subsw_shift ((p), ARMREG_RZR, (rn), (rm), (shift_type), (amount))
+#define arm_negx_shift(p, rd, rm, shift_type, amount) arm_subx_shift ((p), (rd), ARMREG_RZR, (rm), (shift_type), (amount))
+#define arm_negw_shift(p, rd, rm, shift_type, amount) arm_subw_shift ((p), (rd), ARMREG_RZR, (rm), (shift_type), (amount))
+#define arm_negsx_shift(p, rd, rm, shift_type, amount) arm_subsx_shift ((p), (rd), ARMREG_RZR, (rm), (shift_type), (amount))
+#define arm_negsw_shift(p, rd, rm, shift_type, amount) arm_subsw_shift ((p), (rd), ARMREG_RZR, (rm), (shift_type), (amount))
+
+#define arm_addx(p, rd, rn, rm) arm_addx_shift ((p), (rd), (rn), (rm), 0, 0)
+#define arm_addw(p, rd, rn, rm) arm_addw_shift ((p), (rd), (rn), (rm), 0, 0)
+#define arm_subx(p, rd, rn, rm) arm_subx_shift ((p), (rd), (rn), (rm), 0, 0)
+#define arm_subw(p, rd, rn, rm) arm_subw_shift ((p), (rd), (rn), (rm), 0, 0)
+#define arm_addsx(p, rd, rn, rm) arm_addsx_shift ((p), (rd), (rn), (rm), 0, 0)
+#define arm_addsw(p, rd, rn, rm) arm_addsw_shift ((p), (rd), (rn), (rm), 0, 0)
+#define arm_subsx(p, rd, rn, rm) arm_subsx_shift ((p), (rd), (rn), (rm), 0, 0)
+#define arm_subsw(p, rd, rn, rm) arm_subsw_shift ((p), (rd), (rn), (rm), 0, 0)
+#define arm_cmpx(p, rd, rn) arm_cmpx_shift ((p), (rd), (rn), 0, 0)
+#define arm_cmpw(p, rd, rn) arm_cmpw_shift ((p), (rd), (rn), 0, 0)
+#define arm_negx(p, rd, rn) arm_negx_shift ((p), (rd), (rn), 0, 0)
+#define arm_negw(p, rd, rn) arm_negw_shift ((p), (rd), (rn), 0, 0)
+
+/* Arithmetic with carry */
+#define arm_format_adc(p, sf, op, S, rd, rn, rm) arm_emit ((p), ((sf) << 31) | ((op) << 30) | ((S) << 29) | (0xd0 << 21) | ((rm) << 16) | (0x0 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_adcx(p, rd, rn, rm) arm_format_adc ((p), 0x1, 0x0, 0x0, (rd), (rn), (rm))
+#define arm_adcw(p, rd, rn, rm) arm_format_adc ((p), 0x0, 0x0, 0x0, (rd), (rn), (rm))
+#define arm_adcsx(p, rd, rn, rm) arm_format_adc ((p), 0x1, 0x0, 0x1, (rd), (rn), (rm))
+#define arm_adcsw(p, rd, rn, rm) arm_format_adc ((p), 0x0, 0x0, 0x1, (rd), (rn), (rm))
+#define arm_sbcx(p, rd, rn, rm) arm_format_adc ((p), 0x1, 0x1, 0x0, (rd), (rn), (rm))
+#define arm_sbcw(p, rd, rn, rm) arm_format_adc ((p), 0x0, 0x1, 0x0, (rd), (rn), (rm))
+#define arm_sbcsx(p, rd, rn, rm) arm_format_adc ((p), 0x1, 0x1, 0x1, (rd), (rn), (rm))
+#define arm_sbcsw(p, rd, rn, rm) arm_format_adc ((p), 0x0, 0x1, 0x1, (rd), (rn), (rm))
+#define arm_ngcx(p, rd, rm) arm_sbcx ((p), (rd), ARMREG_RZR, (rm))
+#define arm_ngcw(p, rd, rm) arm_sbcw ((p), (rd), ARMREG_RZR, (rm))
+#define arm_ngcsx(p, rd, rm) arm_sbcsx ((p), (rd), ARMREG_RZR, (rm))
+#define arm_ngcsw(p, rd, rm) arm_sbcsw ((p), (rd), ARMREG_RZR, (rm))
+
+/* Logical (shifted register) */
+#define arm_format_logical_shift(p, sf, op, N, rd, rn, rm, shift, imm6) arm_emit ((p), ((sf) << 31) | ((op) << 29) | (0xa << 24) | ((shift) << 22) | ((N) << 21) | ((rm) << 16) | ((imm6) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_andx_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x1, 0x0, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_andw_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x0, 0x0, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_andsx_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x1, 0x3, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_andsw_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x0, 0x3, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_bicx_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x1, 0x0, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_bicw_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x0, 0x0, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_bicsx_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x1, 0x3, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_bicsw_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x0, 0x3, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_eonx_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x1, 0x2, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_eonw_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x0, 0x2, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_eorx_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x1, 0x2, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_eorw_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x0, 0x2, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_orrx_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x1, 0x1, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_orrw_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x0, 0x1, 0x0, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_ornx_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x1, 0x1, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_ornw_shift(p, rd, rn, rm, shift_type, amount) arm_format_logical_shift ((p), 0x0, 0x1, 0x1, (rd), (rn), (rm), (shift_type), (amount))
+#define arm_mvnx_shift(p, rd, rm, shift_type, amount) arm_ornx_shift ((p), (rd), ARMREG_RZR, (rm), (shift_type), (amount))
+#define arm_mvnw_shift(p, rd, rm, shift_type, amount) arm_ornw_shift ((p), (rd), ARMREG_RZR, (rm), (shift_type), (amount))
+#define arm_tstx_shift(p, rn, rm, shift_type, amount) arm_andsx_shift ((p), ARMREG_RZR, (rn), (rm), (shift_type), (amount))
+#define arm_tstw_shift(p, rn, rm, shift_type, amount) arm_andsw_shift ((p), ARMREG_RZR, (rn), (rm), (shift_type), (amount))
+/* Aliases */
+#define arm_andx(p, rd, rn, rm) arm_andx_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_andw(p, rd, rn, rm) arm_andw_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_andsx(p, rd, rn, rm) arm_andsx_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_andsw(p, rd, rn, rm) arm_andsw_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_bixx(p, rd, rn, rm) arm_bixx_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_bixw(p, rd, rn, rm) arm_bixw_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_bixsx(p, rd, rn, rm) arm_bixsx_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_bixsw(p, rd, rn, rm) arm_bixsw_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_eonx(p, rd, rn, rm) arm_eonx_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_eonw(p, rd, rn, rm) arm_eonw_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_eorx(p, rd, rn, rm) arm_eorx_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_eorw(p, rd, rn, rm) arm_eorw_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_orrx(p, rd, rn, rm) arm_orrx_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_orrw(p, rd, rn, rm) arm_orrw_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_ornx(p, rd, rn, rm) arm_ornx_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_ornw(p, rd, rn, rm) arm_ornw_shift(p, rd, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_mvnx(p, rd, rm) arm_mvnx_shift(p, rd, rm, ARMSHIFT_LSL, 0)
+#define arm_mvnw(p, rd, rm) arm_mvnw_shift(p, rd, rm, ARMSHIFT_LSL, 0)
+#define arm_tstx(p, rn, rm) arm_tstx_shift(p, rn, rm, ARMSHIFT_LSL, 0)
+#define arm_tstw(p, rn, rm) arm_tstw_shift(p, rn, rm, ARMSHIFT_LSL, 0)
+
+/* Move (register) */
+#define arm_movx(p, rn, rm) arm_orrx_shift ((p), (rn), ARMREG_RZR, (rm), ARMSHIFT_LSL, 0)
+#define arm_movw(p, rn, rm) arm_orrw_shift ((p), (rn), ARMREG_RZR, (rm), ARMSHIFT_LSL, 0)
+
+/* Not an official alias */
+#define arm_movspx(p, rn, rm) arm_addx_imm ((p), (rn), (rm), 0)
+
+/* Shift (register) */
+#define arm_format_shift_reg(p, sf, op2, rd, rn, rm) arm_emit ((p), ((sf) << 31) | (0xd6 << 21) | ((rm) << 16) | (0x2 << 12) | ((op2) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_asrvx(p, rd, rn, rm) arm_format_shift_reg ((p), 0x1, 0x2, (rd), (rn), (rm))
+#define arm_asrvw(p, rd, rn, rm) arm_format_shift_reg ((p), 0x0, 0x2, (rd), (rn), (rm))
+#define arm_lslvx(p, rd, rn, rm) arm_format_shift_reg ((p), 0x1, 0x0, (rd), (rn), (rm))
+#define arm_lslvw(p, rd, rn, rm) arm_format_shift_reg ((p), 0x0, 0x0, (rd), (rn), (rm))
+#define arm_lsrvx(p, rd, rn, rm) arm_format_shift_reg ((p), 0x1, 0x1, (rd), (rn), (rm))
+#define arm_lsrvw(p, rd, rn, rm) arm_format_shift_reg ((p), 0x0, 0x1, (rd), (rn), (rm))
+#define arm_rorvx(p, rd, rn, rm) arm_format_shift_reg ((p), 0x1, 0x3, (rd), (rn), (rm))
+#define arm_rorvw(p, rd, rn, rm) arm_format_shift_reg ((p), 0x0, 0x3, (rd), (rn), (rm))
+
+/* Multiply */
+#define arm_format_mul(p, sf, o0, rd, rn, rm, ra) arm_emit ((p), ((sf) << 31) | (0x0 << 29) | (0x1b << 24) | (0x0 << 21) | ((rm) << 16) | ((o0) << 15) | ((ra) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_maddx(p, rd, rn, rm, ra) arm_format_mul((p), 0x1, 0x0, (rd), (rn), (rm), (ra))
+#define arm_maddw(p, rd, rn, rm, ra) arm_format_mul((p), 0x0, 0x0, (rd), (rn), (rm), (ra))
+#define arm_msubx(p, rd, rn, rm, ra) arm_format_mul((p), 0x1, 0x1, (rd), (rn), (rm), (ra))
+#define arm_msubw(p, rd, rn, rm, ra) arm_format_mul((p), 0x0, 0x1, (rd), (rn), (rm), (ra))
+#define arm_mnegx(p, rd, rn, rm) arm_msubx ((p), (rd), (rn), (rm), ARMREG_RZR)
+#define arm_mnegw(p, rd, rn, rm) arm_msubw ((p), (rd), (rn), (rm), ARMREG_RZR)
+#define arm_mulx(p, rd, rn, rm) arm_maddx ((p), (rd), (rn), (rm), ARMREG_RZR)
+#define arm_mulw(p, rd, rn, rm) arm_maddw ((p), (rd), (rn), (rm), ARMREG_RZR)
+
+/* FIXME: Missing multiple opcodes */
+
+/* Division */
+#define arm_format_div(p, sf, o1, rd, rn, rm) arm_emit ((p), ((sf) << 31) | (0xd6 << 21) | ((rm) << 16) | (0x1 << 11) | ((o1) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_sdivx(p, rd, rn, rm) arm_format_div ((p), 0x1, 0x1, (rd), (rn), (rm))
+#define arm_sdivw(p, rd, rn, rm) arm_format_div ((p), 0x0, 0x1, (rd), (rn), (rm))
+#define arm_udivx(p, rd, rn, rm) arm_format_div ((p), 0x1, 0x0, (rd), (rn), (rm))
+#define arm_udivw(p, rd, rn, rm) arm_format_div ((p), 0x0, 0x0, (rd), (rn), (rm))
+
+/* Conditional select */
+#define arm_format_csel(p, sf, op, op2, cond, rd, rn, rm) arm_emit ((p), ((sf) << 31) | ((op) << 30) | (0xd4 << 21) | ((rm) << 16) | ((cond) << 12) | ((op2) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_cselx(p, cond, rd, rn, rm) arm_format_csel ((p), 0x1, 0x0, 0x0, (cond), (rd), (rn), (rm))
+#define arm_cselw(p, cond, rd, rn, rm) arm_format_csel ((p), 0x0, 0x0, 0x0, (cond), (rd), (rn), (rm))
+#define arm_csincx(p, cond, rd, rn, rm) arm_format_csel ((p), 0x1, 0x0, 0x1, (cond), (rd), (rn), (rm))
+#define arm_csincw(p, cond, rd, rn, rm) arm_format_csel ((p), 0x0, 0x0, 0x1, (cond), (rd), (rn), (rm))
+#define arm_csinvx(p, cond, rd, rn, rm) arm_format_csel ((p), 0x1, 0x1, 0x0, (cond), (rd), (rn), (rm))
+#define arm_csinvw(p, cond, rd, rn, rm) arm_format_csel ((p), 0x0, 0x1, 0x0, (cond), (rd), (rn), (rm))
+#define arm_csnegx(p, cond, rd, rn, rm) arm_format_csel ((p), 0x1, 0x1, 0x1, (cond), (rd), (rn), (rm))
+#define arm_csnegw(p, cond, rd, rn, rm) arm_format_csel ((p), 0x0, 0x1, 0x1, (cond), (rd), (rn), (rm))
+
+#define arm_cset(p, cond, rd) arm_csincx ((p), ((cond) ^ 0x1), (rd), ARMREG_RZR, ARMREG_RZR)
+
+/* C5.6.68 (HINT) */
+#define arm_hint(p, imm) arm_emit ((p), (0xd5032 << 12) | ((imm) << 5) | (0x1f << 0))
+#define arm_nop(p) arm_hint ((p), 0x0)
+
+/* C5.6.29 BRK */
+#define arm_brk(p, imm) arm_emit ((p), (0xd4 << 24) | (0x1 << 21) | ((imm) << 5))
+
+/* C6.3.114 FMOV (General) */
+#define arm_format_fmov_gr(p, sf, type, rmode, opcode, rn, rd) arm_emit ((p), ((sf) << 31) | (0x1e << 24) | ((type) << 22) | (0x1 << 21) | ((rmode) << 19) | ((opcode) << 16) | ((rn) << 5) | ((rd) << 0))
+
+/* Move gr->vfp */
+#define arm_fmov_rx_to_double(p, dd, xn) arm_format_fmov_gr ((p), 0x1, 0x1, 0x0, 0x7, (xn), (dd))
+
+/* Move vfp->gr */
+#define arm_fmov_double_to_rx(p, xd, dn) arm_format_fmov_gr ((p), 0x1, 0x1, 0x0, 0x6, (dn), (xd))
+
+/* C6.3.113 FMOV (register) */
+#define arm_format_fmov(p, type, rn, rd) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | (0x10 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_fmovd(p, dd, dn) arm_format_fmov ((p), 0x1, (dn), (dd))
+#define arm_fmovs(p, dd, dn) arm_format_fmov ((p), 0x0, (dn), (dd))
+
+/* C6.3.54 FCMP */
+#define arm_format_fcmp(p, type, opc, rn, rm) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | ((rm) << 16) | (0x8 << 10) | ((rn) << 5) | ((opc) << 3))
+
+#define arm_fcmpd(p, dn, dm) arm_format_fcmp (p, 0x1, 0x0, (dn), (dm))
+#define arm_fcmps(p, dn, dm) arm_format_fcmp (p, 0x0, 0x0, (dn), (dm))
+
+/* Float precision */
+#define arm_format_fcvt(p, type, opc, rn, rd) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | (0x1 << 17) | ((opc) << 15) | (0x10 << 10) | ((rn) << 5) | ((rd) << 0))
+
+/* C6.3.57 FCVT */
+/* single->double */
+#define arm_fcvt_sd(p, dd, sn) arm_format_fcvt ((p), 0x0, 0x1, (sn), (dd))
+/* double->single */
+#define arm_fcvt_ds(p, sd, dn) arm_format_fcvt ((p), 0x1, 0x0, (dn), (sd))
+
+/* Float conversion to integer conversion */
+#define arm_format_fcvtz(p, sf, type, rmode, opcode, rn, rd) arm_emit ((p), ((sf) << 31) | (0x1e << 24) | ((type) << 22) | (0x1 << 21) | ((rmode) << 19) | ((opcode) << 16) | ((rn) << 5) | ((rd) << 0))
+
+/* C6.3.80 FCVTZS (scalar, integer) */
+#define arm_fcvtzs_dw(p, rd, rn) arm_format_fcvtz ((p), 0x0, 0x1, 0x3, 0x0, (rn), (rd))
+#define arm_fcvtzs_dx(p, rd, rn) arm_format_fcvtz ((p), 0x1, 0x1, 0x3, 0x0, (rn), (rd))
+#define arm_fcvtzs_sw(p, rd, rn) arm_format_fcvtz ((p), 0x0, 0x0, 0x3, 0x0, (rn), (rd))
+#define arm_fcvtzs_sx(p, rd, rn) arm_format_fcvtz ((p), 0x1, 0x0, 0x3, 0x0, (rn), (rd))
+
+/* C6.3.84 FCVTZU (scalar, integer) */
+#define arm_fcvtzu_dw(p, rd, rn) arm_format_fcvtz ((p), 0x0, 0x1, 0x3, 0x1, (rn), (rd))
+#define arm_fcvtzu_dx(p, rd, rn) arm_format_fcvtz ((p), 0x1, 0x1, 0x3, 0x1, (rn), (rd))
+#define arm_fcvtzu_sw(p, rd, rn) arm_format_fcvtz ((p), 0x0, 0x0, 0x3, 0x1, (rn), (rd))
+#define arm_fcvtzu_sx(p, rd, rn) arm_format_fcvtz ((p), 0x1, 0x0, 0x3, 0x1, (rn), (rd))
+
+/* C6.3.208 SCVTF (vector, integer) */
+#define arm_format_scvtf_vector(p, sz, rn, rd) arm_emit ((p), (0x1 << 30) | (0x0 << 29) | (0x1e << 24) | ((sz) << 22) | (0x10 << 17) | (0x1d << 12) | (0x2 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_scvtf_d(p, dd, dn) arm_format_scvtf_vector ((p), 0x1, (dn), (dd))
+#define arm_scvtf_s(p, sd, sn) arm_format_scvtf_vector ((p), 0x0, (sn), (sd))
+
+/* C6.3.210 SCVTF (scalar, integer) */
+#define arm_format_scvtf_scalar(p, sf, type, rn, rd) arm_emit ((p), ((sf) << 31) | (0x1e << 24) | ((type) << 22) | (0x1 << 21) | (0x2 << 16) | (0x0 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_scvtf_rx_to_d(p, dd, rn) arm_format_scvtf_scalar ((p), 0x1, 0x1, rn, dd)
+#define arm_scvtf_rw_to_d(p, dd, rn) arm_format_scvtf_scalar ((p), 0x0, 0x1, rn, dd)
+#define arm_scvtf_rx_to_s(p, dd, rn) arm_format_scvtf_scalar ((p), 0x1, 0x0, rn, dd)
+#define arm_scvtf_rw_to_s(p, dd, rn) arm_format_scvtf_scalar ((p), 0x0, 0x0, rn, dd)
+
+/* C6.3.306 UCVTF (vector, integer) */
+#define arm_format_ucvtf_vector(p, sz, rn, rd) arm_emit ((p), (0x1 << 30) | (0x1 << 29) | (0x1e << 24) | ((sz) << 22) | (0x10 << 17) | (0x1d << 12) | (0x2 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_ucvtf_d(p, dd, dn) arm_format_ucvtf_vector ((p), 0x1, (dn), (dd))
+#define arm_ucvtf_s(p, sd, sn) arm_format_ucvtf_vector ((p), 0x0, (sn), (sd))
+
+/* C6.3.308 UCVTF (scalar, integer) */
+#define arm_format_ucvtf_scalar(p, sf, type, rn, rd) arm_emit ((p), ((sf) << 31) | (0x1e << 24) | ((type) << 22) | (0x1 << 21) | (0x3 << 16) | (0x0 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_ucvtf_rx_to_d(p, dd, rn) arm_format_ucvtf_scalar ((p), 0x1, 0x1, rn, dd)
+#define arm_ucvtf_rw_to_d(p, dd, rn) arm_format_ucvtf_scalar ((p), 0x0, 0x1, rn, dd)
+
+/* C6.3.41 FADD (scalar) */
+#define arm_format_fadd_scalar(p, type, rd, rn, rm) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | ((rm) << 16) | (0x1 << 13) | (0x2 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_fadd_d(p, rd, rn, rm) arm_format_fadd_scalar ((p), 0x1, (rd), (rn), (rm))
+#define arm_fadd_s(p, rd, rn, rm) arm_format_fadd_scalar ((p), 0x0, (rd), (rn), (rm))
+
+/* C6.3.149 FSUB (scalar) */
+#define arm_format_fsub_scalar(p, type, rd, rn, rm) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | ((rm) << 16) | (0x1 << 13) | (0x1 << 12) | (0x2 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_fsub_d(p, rd, rn, rm) arm_format_fsub_scalar ((p), 0x1, (rd), (rn), (rm))
+#define arm_fsub_s(p, rd, rn, rm) arm_format_fsub_scalar ((p), 0x0, (rd), (rn), (rm))
+
+/* C6.3.119 FMUL (scalar) */
+#define arm_format_fmul_scalar(p, type, rd, rn, rm) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | ((rm) << 16) | (0x2 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_fmul_d(p, rd, rn, rm) arm_format_fmul_scalar ((p), 0x1, (rd), (rn), (rm))
+#define arm_fmul_s(p, rd, rn, rm) arm_format_fmul_scalar ((p), 0x0, (rd), (rn), (rm))
+
+/* C6.3.86 FDIV (scalar) */
+#define arm_format_fdiv_scalar(p, type, rd, rn, rm) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | ((rm) << 16) | (0x1 << 12) | (0x2 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_fdiv_d(p, rd, rn, rm) arm_format_fdiv_scalar ((p), 0x1, (rd), (rn), (rm))
+#define arm_fdiv_s(p, rd, rn, rm) arm_format_fdiv_scalar ((p), 0x0, (rd), (rn), (rm))
+
+/* C6.3.116 FMSUB */
+#define arm_format_fmsub(p, type, rd, rn, rm, ra) arm_emit ((p), (0x1f << 24) | ((type) << 22) | (0x0 << 21) | ((rm) << 16) | (0x1 << 15) | ((ra) << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_fmsub_d(p, rd, rn, rm, ra) arm_format_fmsub ((p), 0x1, (rd), (rn), (rm), (ra))
+
+/* C6.3.123 FNEG */
+#define arm_format_fneg(p, type, rd, rn) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | (0x2 << 15) | (0x10 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_fneg_d(p, rd, rn) arm_format_fneg ((p), 0x1, (rd), (rn))
+#define arm_fneg_s(p, rd, rn) arm_format_fneg ((p), 0x0, (rd), (rn))
+
+/* C6.3.37 FABS (scalar) */
+#define arm_format_fabs(p, type, opc, rd, rn) arm_emit ((p), (0x1e << 24) | ((type) << 22) | (0x1 << 21) | ((opc) << 15) | (0x10 << 10) | ((rn) << 5) | ((rd) << 0))
+
+#define arm_fabs_d(p, rd, rn) arm_format_fabs ((p), 0x1, 0x1, (rd), (rn))
+
+/* C5.6.60 DMB */
+#define arm_format_dmb(p, opc, CRm) arm_emit ((p), (0x354 << 22) | (0x3 << 16) | (0x3 << 12) | ((CRm) << 8) | (0x1 << 7) | ((opc) << 5) | (0x1f << 0))
+
+#define ARM_DMB_LD 0x1
+#define ARM_DMB_ST 0x2
+#define ARM_DMB_ALL 0x3
+#define ARM_DMB_SY 0xc
+
+#define arm_dmb(p, imm) arm_format_dmb ((p), 0x1, (imm))
+
+/* C5.6.129 MRS */
+
+#define ARM_MRS_REG_TPIDR_EL0 0x5e82
+
+#define arm_format_mrs(p, sysreg, rt) arm_emit ((p), (0x354 << 22) | (0x1 << 21) | (0x1 << 20) | ((sysreg) << 5) | ((rt) << 0))
+
+#define arm_mrs(p, rt, sysreg) arm_format_mrs ((p), (sysreg), (rt))
+
+#endif /* __arm_CODEGEN_H__ */
* Copyright (c) 2004 Novell, Inc
* Author: Paolo Molaro (lupus@ximian.com)
*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/* registers */
Copyright (C) 2007-2008 Andreas Faerber
for testing do the following: ./test | as -o test.o
+ Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_PPC_CODEGEN_H__
/*
Copyright (C) 2001 Radek Doulik
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef S390X_H
*
* Copyright (C) 2000 Intel Corporation. All rights reserved.
* Copyright (C) 2001, 2002 Ximian, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef X86_H
* Sebastien Pouliot <sebastien@ximian.com>
*
* Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <glib.h>
* Sebastien Pouliot <sebastien@ximian.com>
*
* Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONODIS_DECLSEC_H__
*
* (C) 2001 Ximian, Inc.
* Copyright 2012 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <stdio.h>
* Structs are not being labeled as `valuetype' classes
*
* How are fields with literals mapped to constants?
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <stdio.h>
*
* (C) 2002-2011 Novell, Inc.
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Dick Porter (dick@ximian.com)
*
* Copyright (c) 2006 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Dick Porter (dick@ximian.com)
*
* Copyright (C) 2006 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _WAPI_IO_PORTABILITY_H_
*
* (C) 2002 Ximian, Inc.
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _WAPI_IO_PRIVATE_H_
* Marek Habersack <grendel@twistedcode.net>
*
* Copyright 2016 Xamarin, Inc (http://xamarin.com/)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __IO_TRACE_H
* (C) 2002 Ximian, Inc.
* Copyright (c) 2002-2006 Novell, Inc.
* Copyright 2011 Xamarin Inc (http://www.xamarin.com).
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* (C) 2002 Ximian, Inc.
* Copyright (c) 2002-2009 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <stdio.h>
* (C) 2002 Ximian, Inc.
* Copyright (c) 2002-2009 Novell, Inc.
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* (C) 2002-2011 Novell, Inc.
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* (C) 2002-2006 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
/*
* Copyright 2014 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_ABI_DETAILS_H__
#define __MONO_METADATA_ABI_DETAILS_H__
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2012 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#undef ASSEMBLY_LOAD_DEBUG
#include <config.h>
mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
- mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
mono_thread_init (start_cb, attach_cb);
if (!mono_error_ok (&error)) {
mono_error_cleanup (&error);
g_free (dir_name);
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
+ mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
return NULL;
}
shadow = get_shadow_assembly_location (filename, &error);
if (!mono_error_ok (&error)) {
mono_error_cleanup (&error);
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
+ mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
return NULL;
}
if (ensure_directory_exists (shadow) == FALSE) {
g_free (shadow);
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
+ mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
return NULL;
}
if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
return NULL; /* file not found, shadow copy failed */
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
+ mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
return NULL;
}
if (copy_result == FALSE) {
g_free (shadow);
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
+ mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
return NULL;
}
/* Create a .ini file containing the original assembly location */
if (!shadow_copy_create_ini (shadow, filename)) {
g_free (shadow);
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
+ mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
return NULL;
}
void
ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
{
+ MonoException *exc = NULL;
MonoDomain * domain = mono_domain_get_by_id (domain_id);
if (NULL == domain) {
- MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
+ mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
mono_set_pending_exception (exc);
return;
}
return;
#endif
- mono_domain_unload (domain);
+ mono_domain_try_unload (domain, (MonoObject**)&exc);
+ if (exc)
+ mono_set_pending_exception (exc);
}
gboolean
{
MonoObject *exc = NULL;
mono_domain_try_unload (domain, &exc);
- if (exc)
- mono_raise_exception ((MonoException*)exc);
}
static guint32
MONO_API void
mono_domain_set_internal (MonoDomain *domain);
+MONO_RT_EXTERNAL_ONLY
MONO_API void
mono_domain_unload (MonoDomain *domain);
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <stdio.h>
* Zoltan Varga (vargaz@gmail.com)
*
* Copyright 2007-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
/*
* Copyright 2012 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_CLASS_INTERNALS_H__
#define __MONO_METADATA_CLASS_INTERNALS_H__
MonoMethod method;
MonoMethodPInvoke pinvoke;
} method;
- MonoMethodHeader *header;
MonoMethod *declaring; /* the generic method definition. */
MonoGenericContext context; /* The current instantiation */
MonoImageSet *owner; /* The image set that the inflated method belongs to. */
typedef gpointer (*MonoRemotingTrampoline) (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target);
typedef gpointer (*MonoDelegateTrampoline) (MonoDomain *domain, MonoClass *klass);
-typedef gpointer (*MonoLookupDynamicToken) (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context);
-
typedef gboolean (*MonoGetCachedClassInfo) (MonoClass *klass, MonoCachedClassInfo *res);
typedef gboolean (*MonoGetClassFromName) (MonoImage *image, const char *name_space, const char *name, MonoClass **res);
mono_classes_cleanup (void);
void
-mono_class_layout_fields (MonoClass *klass);
+mono_class_layout_fields (MonoClass *klass, int instance_size);
void
mono_class_setup_interface_offsets (MonoClass *klass);
mono_install_delegate_trampoline (MonoDelegateTrampoline func);
gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context);
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error);
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean check_token, MonoClass **handle_class, MonoGenericContext *context);
-
-void
-mono_install_lookup_dynamic_token (MonoLookupDynamicToken func);
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean check_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error);
gpointer
mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper);
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#ifdef HAVE_ALLOCA_H
int i, blittable = TRUE;
guint32 real_size = 0;
guint32 packing_size = 0;
+ int instance_size;
gboolean explicit_size;
MonoClassField *field;
MonoGenericContainer *container = NULL;
}
}
- klass->instance_size = 0;
+ instance_size = 0;
if (!klass->rank)
klass->sizes.class_size = 0;
return;
}
}
- klass->instance_size += klass->parent->instance_size;
+ instance_size += klass->parent->instance_size;
klass->min_align = klass->parent->min_align;
/* we use |= since it may have been set already */
klass->has_references |= klass->parent->has_references;
blittable = klass->parent->blittable;
} else {
- klass->instance_size = sizeof (MonoObject);
+ instance_size = sizeof (MonoObject);
klass->min_align = 1;
}
return;
}
klass->packing_size = packing_size;
- real_size += klass->instance_size;
+ real_size += instance_size;
}
if (!top) {
if (explicit_size && real_size) {
- klass->instance_size = MAX (real_size, klass->instance_size);
+ instance_size = MAX (real_size, instance_size);
}
klass->blittable = blittable;
+ if (!klass->instance_size)
+ klass->instance_size = instance_size;
mono_memory_barrier ();
klass->size_inited = 1;
klass->fields_inited = 1;
return;
}
if (explicit_size && real_size) {
- klass->instance_size = MAX (real_size, klass->instance_size);
+ instance_size = MAX (real_size, instance_size);
}
if (mono_class_has_failure (klass))
return;
- mono_class_layout_fields (klass);
+ mono_class_layout_fields (klass, instance_size);
/*valuetypes can't be neither bigger than 1Mb or empty. */
if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
/*
* mono_class_layout_fields:
* @class: a class
+ * @instance_size: base instance size
*
* Compute the placement of fields inside an object or struct, according to
* the layout rules and set the following fields in @class:
* LOCKING: this is supposed to be called with the loader lock held.
*/
void
-mono_class_layout_fields (MonoClass *klass)
+mono_class_layout_fields (MonoClass *klass, int instance_size)
{
int i;
const int top = klass->field.count;
/*
* Compute field layout and total size (not considering static fields)
*/
-
switch (layout) {
case TYPE_ATTRIBUTE_AUTO_LAYOUT:
case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
real_size = field->offset + size;
}
- klass->instance_size = MAX (real_size, klass->instance_size);
+ instance_size = MAX (real_size, instance_size);
- if (klass->instance_size & (klass->min_align - 1)) {
- klass->instance_size += klass->min_align - 1;
- klass->instance_size &= ~(klass->min_align - 1);
+ if (instance_size & (klass->min_align - 1)) {
+ instance_size += klass->min_align - 1;
+ instance_size &= ~(klass->min_align - 1);
}
}
break;
g_free (ref_bitmap);
}
- klass->instance_size = MAX (real_size, klass->instance_size);
- if (klass->instance_size & (klass->min_align - 1)) {
- klass->instance_size += klass->min_align - 1;
- klass->instance_size &= ~(klass->min_align - 1);
+ instance_size = MAX (real_size, instance_size);
+ if (instance_size & (klass->min_align - 1)) {
+ instance_size += klass->min_align - 1;
+ instance_size &= ~(klass->min_align - 1);
}
break;
}
* unaligned accesses otherwise. See #78990 for a testcase.
*/
if (mono_align_small_structs) {
- if (klass->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
- klass->min_align = MAX (klass->min_align, klass->instance_size - sizeof (MonoObject));
+ if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
+ klass->min_align = MAX (klass->min_align, instance_size - sizeof (MonoObject));
}
}
+ if (klass->instance_size && !klass->image->dynamic) {
+ /* Might be already set using cached info */
+ g_assert (klass->instance_size == instance_size);
+ } else {
+ klass->instance_size = instance_size;
+ }
mono_memory_barrier ();
klass->size_inited = 1;
static void
mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
{
+ MonoError error;
MonoMethod **overrides;
MonoGenericContext *context;
guint32 type_token;
* This is true since we don't do layout all over again for them, we simply inflate
* the layout of the parent.
*/
- mono_reflection_get_dynamic_overrides (klass, &overrides, &onum);
+ mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
+ if (!is_ok (&error)) {
+ mono_loader_unlock ();
+ g_list_remove (in_setup, klass);
+ mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf("Could not load list of method overrides due to %s", mono_error_get_message (&error)));
+ mono_error_cleanup (&error);
+ return;
+ }
} else {
/* The following call fails if there are missing methods in the type */
/* FIXME it's probably a good idea to avoid this for generic instances. */
mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
return NULL;
}
- klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/
+ klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
goto done;
}
mono_error_init (error);
//FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
- if (image_is_dynamic (image))
- return mono_class_get_type ((MonoClass *)mono_lookup_dynamic_token (image, type_token, context));
+ if (image_is_dynamic (image)) {
+ MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
+ return_val_if_nok (error, NULL);
+ return mono_class_get_type (klass);
+ }
if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
MonoClass *klass = mono_class_get_checked (image, type_token, error);
gboolean
mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
{
+ MonoError error;
/*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
if (!klass->inited)
mono_class_init (klass);
}
/* interface_offsets might not be set for dynamic classes */
- if (oklass->ref_info_handle && !oklass->interface_bitmap)
+ if (oklass->ref_info_handle && !oklass->interface_bitmap) {
/*
* oklass might be a generic type parameter but they have
* interface_offsets set.
*/
- return mono_reflection_call_is_assignable_to (oklass, klass);
+ gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error);
+ return FALSE;
+ }
+ return result;
+ }
if (!oklass->interface_bitmap)
/* Happens with generic instances of not-yet created dynamic types */
return FALSE;
return TRUE;
if (mono_class_has_variant_generic_params (klass)) {
- MonoError error;
int i;
mono_class_setup_interfaces (oklass, &error);
if (!mono_error_ok (&error)) {
if (image_is_dynamic (image)) {
MonoClass *tmp_handle_class;
- gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
+ gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
+ mono_error_assert_ok (error);
g_assert (tmp_handle_class);
if (handle_class)
*handle_class = tmp_handle_class;
return NULL;
}
-/**
- * This function might need to call runtime functions so it can't be part
- * of the metadata library.
- */
-static MonoLookupDynamicToken lookup_dynamic = NULL;
-
-void
-mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
-{
- lookup_dynamic = func;
-}
-
gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
{
MonoClass *handle_class;
-
- return lookup_dynamic (image, token, TRUE, &handle_class, context);
+ mono_error_init (error);
+ return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
}
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
{
- return lookup_dynamic (image, token, valid_token, handle_class, context);
+ return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
}
static MonoGetCachedClassInfo get_cached_class_info = NULL;
static gpointer
cominterop_get_ccw (MonoObject* object, MonoClass* itf);
+static gpointer
+cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
+
+
static MonoObject*
cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
}
-static void cominterop_raise_hr_exception (int hr)
+static void cominterop_set_hr_error (MonoError *oerror, int hr)
{
static MonoMethod* throw_exception_for_hr = NULL;
MonoError error;
throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_assert_ok (&error);
- mono_raise_exception (ex);
+ mono_error_set_exception_instance (oerror, ex);
}
/**
- * cominterop_get_interface:
+ * cominterop_get_interface_checked:
* @obj: managed wrapper object containing COM object
* @ic: interface type to retrieve for COM object
+ * @error: set on error
*
- * Returns: the COM interface requested
+ * Returns: the COM interface requested. On failure returns NULL and sets @error
*/
static gpointer
-cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
+cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
{
gpointer itf = NULL;
g_assert (ic);
g_assert (MONO_CLASS_IS_INTERFACE (ic));
+ mono_error_init (error);
+
mono_cominterop_lock ();
if (obj->itf_hash)
itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
int hr;
g_assert(found);
hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
- if (hr < 0 && throw_exception) {
- cominterop_raise_hr_exception (hr);
+ if (hr < 0) {
+ cominterop_set_hr_error (error, hr);
}
if (hr >= 0 && itf) {
}
}
+ return itf;
+}
+
+/**
+ * cominterop_get_interface:
+ * @obj: managed wrapper object containing COM object
+ * @ic: interface type to retrieve for COM object
+ *
+ * Returns: the COM interface requested
+ */
+static gpointer
+cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
+{
+ MonoError error;
+ gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
+ if (!is_ok (&error)) {
+ if (throw_exception) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ } else {
+ mono_error_cleanup (&error);
+ }
+ }
+
if (throw_exception)
g_assert (itf);
mono_class_init (klass);
ret = mono_type_get_object_checked (domain, handle, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_set_pending_exception (&error);
return ret;
}
}
static void*
-cominterop_get_idispatch_for_object (MonoObject* object)
+cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
{
+ mono_error_init (error);
if (!object)
return NULL;
if (cominterop_object_is_rcw (object)) {
- return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
- mono_class_get_idispatch_class (), TRUE);
+ return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
+ mono_class_get_idispatch_class (), error);
}
else {
MonoClass* klass = mono_object_class (object);
- if (!cominterop_can_support_dispatch (klass) )
- cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
- return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
+ if (!cominterop_can_support_dispatch (klass) ) {
+ cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
+ return NULL;
+ }
+ return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
}
}
ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
{
#ifndef DISABLE_COM
+ MonoError error;
+
if (!object)
return NULL;
return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
}
else {
- return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
+ void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
+ mono_error_set_pending_exception (&error);
+ return ccw_entry;
}
#else
g_assert_not_reached ();
ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
{
#ifndef DISABLE_COM
- return cominterop_get_idispatch_for_object (object);
+ MonoError error;
+ void* idisp = cominterop_get_idispatch_for_object (object, &error);
+ mono_error_set_pending_exception (&error);
+ return idisp;
#else
g_assert_not_reached ();
#endif
ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
{
#ifndef DISABLE_COM
+ MonoError error;
MonoClass* klass = NULL;
void* itf = NULL;
g_assert (type);
return NULL;
}
- itf = cominterop_get_ccw (object, klass);
- g_assert (itf);
+ itf = cominterop_get_ccw_checked (object, klass, &error);
+ mono_error_set_pending_exception (&error);
return itf;
#else
g_assert_not_reached ();
ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
{
#ifndef DISABLE_COM
+ MonoError error;
MonoClass *klass = mono_type_get_class (type->type);
if (!mono_class_init (klass)) {
mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
return NULL;
}
- return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
+ gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
+ if (throw_exception)
+ mono_error_set_pending_exception (&error);
+ else
+ mono_error_cleanup (&error);
+ return itf;
#else
g_assert_not_reached ();
#endif
}
/**
- * cominterop_get_ccw:
+ * cominterop_get_ccw_checked:
* @object: a pointer to the object
* @itf: interface type needed
+ * @error: set on error
*
* Returns: a value indicating if the object is a
- * Runtime Callable Wrapper (RCW) for a COM object
+ * Runtime Callable Wrapper (RCW) for a COM object.
+ * On failure returns NULL and sets @error.
*/
static gpointer
-cominterop_get_ccw (MonoObject* object, MonoClass* itf)
+cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
{
- MonoError error;
int i;
MonoCCW *ccw = NULL;
MonoCCWInterface* ccw_entry = NULL;
GList *ccw_list, *ccw_list_item;
MonoCustomAttrInfo *cinfo = NULL;
+ mono_error_init (error);
+
if (!object)
return NULL;
g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
mono_cominterop_unlock ();
/* register for finalization to clean up ccw */
- mono_object_register_finalizer (object, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_object_register_finalizer (object, error);
+ return_val_if_nok (error, NULL);
}
- cinfo = mono_custom_attrs_from_class_checked (itf, &error);
- mono_error_assert_ok (&error);
+ cinfo = mono_custom_attrs_from_class_checked (itf, error);
+ mono_error_assert_ok (error);
if (cinfo) {
static MonoClass* coclass_attribute = NULL;
if (!coclass_attribute)
return ccw_entry;
}
+/**
+ * cominterop_get_ccw:
+ * @object: a pointer to the object
+ * @itf: interface type needed
+ *
+ * Returns: a value indicating if the object is a
+ * Runtime Callable Wrapper (RCW) for a COM object
+ */
+static gpointer
+cominterop_get_ccw (MonoObject* object, MonoClass* itf)
+{
+ MonoError error;
+ gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
+ mono_error_set_pending_exception (&error);
+ return ccw_entry;
+}
+
static gboolean
mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
{
cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
{
#ifdef HOST_WIN32
+ MonoError error;
if (!ccw->free_marshaler) {
int ret = 0;
gpointer tunk;
- tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
+ tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
}
/* handle IUnknown special */
if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
- *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
+ *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
+ mono_error_assert_ok (&error);
/* remember to addref on QI */
cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
return MONO_S_OK;
if (!cominterop_can_support_dispatch (klass))
return MONO_E_NOINTERFACE;
- *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
+ *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
+ mono_error_assert_ok (&error);
/* remember to addref on QI */
cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
return MONO_S_OK;
klass_iter = klass_iter->parent;
}
if (itf) {
- *ppv = cominterop_get_ccw (object, itf);
+ *ppv = cominterop_get_ccw_checked (object, itf, &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
+ return MONO_E_NOINTERFACE;
+ }
/* remember to addref on QI */
cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
return MONO_S_OK;
hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
if (hr < 0) {
- cominterop_raise_hr_exception (hr);
+ cominterop_set_hr_error (&error, hr);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
}
if (lbound != 0)
bounded = TRUE;
hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
if (hr < 0) {
- cominterop_raise_hr_exception (hr);
+ cominterop_set_hr_error (&error, hr);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
}
cursize = ubound-lbound+1;
sizes [i] = cursize;
static
gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
{
+ MonoError error;
gpointer result;
#ifdef HOST_WIN32
int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
if (hr < 0) {
- cominterop_raise_hr_exception (hr);
+ cominterop_set_hr_error (&error, hr);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
}
#else
if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
if (hr < 0) {
- cominterop_raise_hr_exception (hr);
+ cominterop_set_hr_error (&error, hr);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
}
} else {
g_assert_not_reached ();
static
gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
{
+ MonoError error;
int i;
int dim = mono_marshal_safearray_get_dim (safearray);
gboolean ret= TRUE;
hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
if (hr < 0) {
- cominterop_raise_hr_exception (hr);
+ cominterop_set_hr_error (&error, hr);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
}
if (++pIndices[i] <= ubound) {
hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
if (hr < 0) {
- cominterop_raise_hr_exception (hr);
+ cominterop_set_hr_error (&error, hr);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
}
pIndices[i] = lbound;
static
void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
{
+ MonoError error;
#ifdef HOST_WIN32
int hr = SafeArrayPutElement (safearray, indices, value);
- if (hr < 0)
- cominterop_raise_hr_exception (hr);
+ if (hr < 0) {
+ cominterop_set_hr_error (&error, hr);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ }
#else
if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
if (hr < 0) {
- cominterop_raise_hr_exception (hr);
+ cominterop_set_hr_error (&error, hr);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
}
} else
g_assert_not_reached ();
* Gonzalo Paniagua Javier (gonzalo@ximian.com)
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _MONO_METADATA_CONSOLEIO_H
* Gonzalo Paniagua Javier (gonzalo@ximian.com)
*
* Copyright (C) 2005-2009 Novell, Inc. (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <mono/metadata/appdomain.h>
* Gonzalo Paniagua Javier (gonzalo@ximian.com)
*
* Copyright (C) 2005-2009 Novell, Inc. (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#if defined(__native_client__)
#include "console-null.c"
method = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
g_assert (method != NULL);
- mono_threadpool_ms_begin_invoke (domain, (MonoObject*) load_value, method, NULL);
+ mono_threadpool_ms_begin_invoke (domain, (MonoObject*) load_value, method, NULL, &error);
+ if (!is_ok (&error)) {
+ g_warning ("Couldn't invoke System.Console cancel handler due to %s", mono_error_get_message (&error));
+ mono_error_cleanup (&error);
+ }
}
static int need_cancel = FALSE;
* Gonzalo Paniagua Javier (gonzalo@ximian.com)
*
* Copyright (C) 2005-2009 Novell, Inc. (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Kornel Pal <http://www.kornelpal.hu/>
*
* Copyright (C) 2008 Kornel Pal
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Kornel Pal <http://www.kornelpal.hu/>
*
* Copyright (C) 2008 Kornel Pal
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_COREE_H__
* Mono Project (http://www.mono-project.com)
*
* Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <string.h>
* Mono Project (http://www.mono-project.com)
*
* Copyright 2015 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Mono Project (http://www.mono-project.com)
*
* Copyright 2015 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_DEBUG_MONO_PPDB_H__
*
* Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* This header is only installed for use by the debugger:
* the structures and the API declared here are not supported.
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_DEBUG_MONO_SYMFILE_H__
/*
* Appdomain-related internal data structures and functions.
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_DOMAIN_INTERNALS_H__
#define __MONO_METADATA_DOMAIN_INTERNALS_H__
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
mono_loader_cleanup ();
mono_classes_cleanup ();
mono_assemblies_cleanup ();
- mono_images_cleanup ();
mono_debug_cleanup ();
+ mono_images_cleanup ();
mono_metadata_cleanup ();
mono_native_tls_free (appdomain_thread_id);
*
* Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <glib.h>
mono_raise_exception (ex);
}
-void
+/**
+ * mono_error_set_pending_exception:
+ * @error: The error
+ *
+ *
+ * If @error is set, convert it to an exception and set the pending exception for the current icall.
+ * Returns TRUE if @error was set, or FALSE otherwise, so that you can write:
+ * if (mono_error_set_pending_exception (error)) {
+ * { ... cleanup code ... }
+ * return;
+ * }
+ */
+gboolean
mono_error_set_pending_exception (MonoError *error)
{
MonoException *ex = mono_error_convert_to_exception (error);
- if (ex)
+ if (ex) {
mono_set_pending_exception (ex);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
}
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* (C) 2001 Ximian, Inc.
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _MONO_METADATA_FILEIO_H_
* Rodrigo Kumpera
*
* Copyright 2014 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Rodrigo Kumpera
*
* Copyright 2014 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Rodrigo Kumpera
*
* Copyright 2014 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _MONO_METADATA_FILE_MMAP_H_
* Gonzalo Paniagua Javier (gonzalo@ximian.com)
*
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifdef HAVE_CONFIG_H
*
* (C) 2002 Ximian, Inc.
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_GC_INTERNAL_H__
*
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/sgen/gc-internal-agnostic.h"
* Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-coop-semaphore.h>
+#include <mono/utils/hazard-pointer.h>
#ifndef HOST_WIN32
#include <pthread.h>
mono_coop_sem_post (&finalizer_sem);
}
+/*
+This is the number of entries allowed in the hazard free queue before
+we explicitly cycle the finalizer thread to trigger pumping the queue.
+
+It was picked empirically by running the corlib test suite in a stress
+scenario where all hazard entries are queued.
+
+In this extreme scenario we double the number of times we cycle the finalizer
+thread compared to just GC calls.
+
+Entries are usually in the order of 100's of bytes each, so we're limiting
+floating garbage to be in the order of a dozen kb.
+*/
+static gboolean finalizer_thread_pulsed;
+#define HAZARD_QUEUE_OVERFLOW_SIZE 20
+
+static void
+hazard_free_queue_is_too_big (size_t size)
+{
+ if (size < HAZARD_QUEUE_OVERFLOW_SIZE)
+ return;
+
+ if (finalizer_thread_pulsed || InterlockedCompareExchange (&finalizer_thread_pulsed, TRUE, FALSE))
+ return;
+
+ mono_gc_finalize_notify ();
+}
+
+static void
+hazard_free_queue_pump (void)
+{
+ mono_thread_hazardous_try_free_all ();
+ finalizer_thread_pulsed = FALSE;
+}
+
#ifdef HAVE_BOEHM_GC
static void
{
gboolean wait = TRUE;
+ /* Register a hazard free queue pump callback */
+ mono_hazard_pointer_install_free_queue_size_callback (hazard_free_queue_is_too_big);
+
while (!finished) {
/* Wait to be notified that there's at least one
* finaliser to run
reference_queue_proccess_all ();
+ hazard_free_queue_pump ();
+
/* Avoid posting the pending done event until there are pending finalizers */
if (mono_coop_sem_timedwait (&finalizer_sem, 0, MONO_SEM_FLAGS_NONE) == 0) {
/* Don't wait again at the start of the loop */
* - Ludovic Henry <ludovic@xamarin.com>
*
* Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* - Ludovic Henry <ludovic@xamarin.com>
*
* Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_HANDLE_H__
return mono_handle_arena_elevate (mono_handle_arena_current (), handle);
}
-#ifndef CHECKED_BUILD
+#ifndef ENABLE_CHECKED_BUILD
#define mono_handle_obj(handle) ((handle)->__private_obj)
ICALL(PROCESS_13, "ShellExecuteEx_internal(System.Diagnostics.ProcessStartInfo,System.Diagnostics.Process/ProcInfo&)", ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal)
#endif /* !DISABLE_PROCESS_HANDLING */
-ICALL_TYPE(SFRAME, "System.Diagnostics.StackFrame", SFRAME_1)
-ICALL(SFRAME_1, "GetILOffsetFromFile", ves_icall_System_StackFrame_GetILOffsetFromFile)
-
ICALL_TYPE(STOPWATCH, "System.Diagnostics.Stopwatch", STOPWATCH_1)
ICALL(STOPWATCH_1, "GetTimestamp", mono_100ns_ticks)
ICALL(ASSEMB_2, "basic_init", mono_image_basic_init)
ICALL_TYPE(CATTRB, "System.Reflection.Emit.CustomAttributeBuilder", CATTRB_1)
-ICALL(CATTRB_1, "GetBlob", mono_reflection_get_custom_attrs_blob)
+ICALL(CATTRB_1, "GetBlob", ves_icall_System_Reflection_Emit_CustomAttributeBuilder_GetBlob)
#ifndef DISABLE_REFLECTION_EMIT
ICALL_TYPE(DERIVEDTYPE, "System.Reflection.Emit.DerivedType", DERIVEDTYPE_1)
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011-2015 Xamarin Inc (http://www.xamarin.com).
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
ICALL_EXPORT MonoObject *
ves_icall_System_Array_GetValueImpl (MonoArray *arr, guint32 pos)
{
+ MonoError error;
MonoClass *ac;
gint32 esize;
gpointer *ea;
+ MonoObject *result = NULL;
ac = (MonoClass *)arr->obj.vtable->klass;
esize = mono_array_element_size (ac);
ea = (gpointer*)((char*)arr->vector + (pos * esize));
- if (ac->element_class->valuetype)
- return mono_value_box (arr->obj.vtable->domain, ac->element_class, ea);
- else
- return (MonoObject *)*ea;
+ if (ac->element_class->valuetype) {
+ result = mono_value_box_checked (arr->obj.vtable->domain, ac->element_class, ea, &error);
+ mono_error_set_pending_exception (&error);
+ } else
+ result = (MonoObject *)*ea;
+ return result;
}
ICALL_EXPORT MonoObject *
ICALL_EXPORT void
ves_icall_System_Array_SetValueImpl (MonoArray *arr, MonoObject *value, guint32 pos)
{
+ MonoError error;
MonoClass *ac, *vc, *ec;
gint32 esize, vsize;
gpointer *ea, *va;
gint64 i64 = 0;
gdouble r64 = 0;
+ mono_error_init (&error);
+
if (value)
vc = value->vtable->klass;
else
}
if (!ec->valuetype) {
- if (!mono_object_isinst (value, ec))
+ gboolean castOk = (NULL != mono_object_isinst_checked (value, ec, &error));
+ if (mono_error_set_pending_exception (&error))
+ return;
+ if (!castOk)
INVALID_CAST;
mono_gc_wbarrier_set_arrayref (arr, ea, (MonoObject*)value);
return;
}
- if (mono_object_isinst (value, ec)) {
+ if (mono_object_isinst_checked (value, ec, &error)) {
if (ec->has_references)
mono_value_copy (ea, (char*)value + sizeof (MonoObject), ec);
else
mono_gc_memmove_atomic (ea, (char *)value + sizeof (MonoObject), esize);
return;
}
+ if (mono_error_set_pending_exception (&error))
+ return;
if (!vc->valuetype)
INVALID_CAST;
return result;
}
+ICALL_EXPORT MonoArray*
+ves_icall_System_Reflection_Emit_CustomAttributeBuilder_GetBlob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues)
+{
+ MonoError error;
+ MonoArray *result = mono_reflection_get_custom_attrs_blob_checked (assembly, ctor, ctorArgs, properties, propValues, fields, fieldValues, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
static gboolean
get_caller (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
{
MonoError error;
MonoClass *klass = mono_class_from_mono_type (type->type);
mono_class_init_checked (klass, &error);
- mono_error_raise_exception (&error);
- return mono_object_isinst (obj, klass) != NULL;
+ if (!is_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return FALSE;
+ }
+ guint32 result = (mono_object_isinst_checked (obj, klass, &error) != NULL);
+ mono_error_set_pending_exception (&error);
+ return result;
}
ICALL_EXPORT guint32
return NULL;
}
- if (mono_security_core_clr_enabled ())
- mono_security_core_clr_ensure_reflection_access_field (cf);
+ if (mono_security_core_clr_enabled () &&
+ !mono_security_core_clr_ensure_reflection_access_field (cf, &error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
MonoObject * result = mono_field_get_value_object_checked (domain, cf, obj, &error);
mono_error_set_pending_exception (&error);
return;
}
- if (mono_security_core_clr_enabled ())
- mono_security_core_clr_ensure_reflection_access_field (cf);
+ if (mono_security_core_clr_enabled () &&
+ !mono_security_core_clr_ensure_reflection_access_field (cf, &error)) {
+ mono_error_set_pending_exception (&error);
+ return;
+ }
type = mono_field_get_type_checked (cf, &error);
if (!mono_error_ok (&error)) {
types [i] = t->type;
}
- geninst = mono_reflection_bind_generic_parameters (type, count, types);
+ geninst = mono_reflection_bind_generic_parameters (type, count, types, &error);
g_free (types);
- if (!geninst)
+ if (!geninst) {
+ mono_error_set_pending_exception (&error);
return NULL;
+ }
klass = mono_class_from_mono_type (geninst);
*exc = NULL;
- if (mono_security_core_clr_enabled ())
- mono_security_core_clr_ensure_reflection_access_method (m);
+ if (mono_security_core_clr_enabled () &&
+ !mono_security_core_clr_ensure_reflection_access_method (m, &error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
if (!(m->flags & METHOD_ATTRIBUTE_STATIC)) {
if (!mono_class_vtable_full (mono_object_domain (method), m->klass, &error)) {
}
if (this_arg) {
- if (!mono_object_isinst (this_arg, m->klass)) {
+ if (!mono_object_isinst_checked (this_arg, m->klass, &error)) {
+ if (!is_ok (&error)) {
+ mono_gc_wbarrier_generic_store (exc, (MonoObject*) mono_error_convert_to_exception (&error));
+ return NULL;
+ }
char *this_name = mono_type_get_full_name (mono_object_get_class (this_arg));
char *target_name = mono_type_get_full_name (m->klass);
char *msg = g_strdup_printf ("Object of type '%s' doesn't match target type '%s'", this_name, target_name);
ICALL_EXPORT MonoObject *
ves_icall_InternalExecute (MonoReflectionMethod *method, MonoObject *this_arg, MonoArray *params, MonoArray **outArgs)
{
+ MonoError error;
MonoDomain *domain = mono_object_domain (method);
MonoMethod *m = method->method;
MonoMethodSignature *sig = mono_method_signature (m);
MonoClassField* field = mono_class_get_field_from_name (k, str);
if (field) {
MonoClass *field_klass = mono_class_from_mono_type (field->type);
- if (field_klass->valuetype)
- result = mono_value_box (domain, field_klass, (char *)this_arg + field->offset);
- else
+ if (field_klass->valuetype) {
+ result = mono_value_box_checked (domain, field_klass, (char *)this_arg + field->offset, &error);
+ mono_error_set_pending_exception (&error);
+ /* fallthru to cleanup */
+ } else
result = (MonoObject *)*((gpointer *)((char *)this_arg + field->offset));
out_args = mono_array_new (domain, mono_defaults.object_class, 1);
mono_ptr_array_destroy (tmp_array);
- if (!str)
- g_free (str);
+ g_free (str);
return res;
}
if (!exportedOnly || mono_module_type_is_visible (tdef, image, i + 1)) {
klass = mono_class_get_checked (image, (i + 1) | MONO_TOKEN_TYPE_DEF, error);
mono_loader_assert_no_error (); /* Plug any leaks */
- mono_error_assert_ok (error);
if (klass) {
rt = mono_type_get_object_checked (domain, &klass->byval_arg, error);
mono_metadata_decode_blob_size (sig, &sig);
return (*sig != 0x6);
} else {
+ MonoError error;
MonoClass *handle_class;
- if (!mono_lookup_dynamic_token_class (image, token, FALSE, &handle_class, NULL))
+ if (!mono_lookup_dynamic_token_class (image, token, FALSE, &handle_class, NULL, &error)) {
+ mono_error_cleanup (&error); /* just probing, ignore error */
return FALSE;
+ }
return mono_defaults.methodhandle_class == handle_class;
}
if (image_is_dynamic (image)) {
if ((table == MONO_TABLE_TYPEDEF) || (table == MONO_TABLE_TYPEREF)) {
- klass = (MonoClass *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);
+ klass = (MonoClass *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL, &error);
+ mono_error_cleanup (&error);
return klass ? &klass->byval_arg : NULL;
}
init_generic_context_from_args (&context, type_args, method_args);
- klass = (MonoClass *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, &context);
+ klass = (MonoClass *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, &context, &error);
+ mono_error_cleanup (&error);
return klass ? &klass->byval_arg : NULL;
}
}
if (image_is_dynamic (image)) {
- if (table == MONO_TABLE_METHOD)
- return (MonoMethod *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);
+ if (table == MONO_TABLE_METHOD) {
+ method = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL, &error);
+ mono_error_cleanup (&error);
+ return method;
+ }
if ((table == MONO_TABLE_MEMBERREF) && !(mono_memberref_is_method (image, token))) {
*resolve_error = ResolveTokenError_BadTable;
}
init_generic_context_from_args (&context, type_args, method_args);
- return (MonoMethod *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, &context);
+ method = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, &context, &error);
+ mono_error_cleanup (&error);
+ return method;
}
if ((index <= 0) || (index > image->tables [table].rows)) {
}
ICALL_EXPORT MonoString*
-ves_icall_System_Reflection_Module_ResolveStringToken (MonoImage *image, guint32 token, MonoResolveTokenError *error)
+ves_icall_System_Reflection_Module_ResolveStringToken (MonoImage *image, guint32 token, MonoResolveTokenError *resolve_error)
{
+ MonoError error;
int index = mono_metadata_token_index (token);
- *error = ResolveTokenError_Other;
+ *resolve_error = ResolveTokenError_Other;
/* Validate token */
if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
- *error = ResolveTokenError_BadTable;
+ *resolve_error = ResolveTokenError_BadTable;
return NULL;
}
- if (image_is_dynamic (image))
- return (MonoString *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);
+ if (image_is_dynamic (image)) {
+ MonoString * result = (MonoString *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL, &error);
+ mono_error_cleanup (&error);
+ return result;
+ }
if ((index <= 0) || (index >= image->heap_us.size)) {
- *error = ResolveTokenError_OutOfRange;
+ *resolve_error = ResolveTokenError_OutOfRange;
return NULL;
}
}
if (image_is_dynamic (image)) {
- if (table == MONO_TABLE_FIELD)
- return (MonoClassField *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);
+ if (table == MONO_TABLE_FIELD) {
+ field = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL, &error);
+ mono_error_cleanup (&error);
+ return field;
+ }
if (mono_memberref_is_method (image, token)) {
*resolve_error = ResolveTokenError_BadTable;
}
init_generic_context_from_args (&context, type_args, method_args);
- return (MonoClassField *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, &context);
+ field = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, FALSE, NULL, &context, &error);
+ mono_error_cleanup (&error);
+ return field;
}
if ((index <= 0) || (index > image->tables [table].rows)) {
mono_class_init_checked (delegate_class, &error);
mono_error_raise_exception (&error);
- mono_assert (delegate_class->parent == mono_defaults.multicastdelegate_class);
+ if (!(delegate_class->parent == mono_defaults.multicastdelegate_class)) {
+ /* FIXME improve this exception message */
+ mono_error_set_execution_engine (&error, "file %s: line %d (%s): assertion failed: (%s)", __FILE__, __LINE__,
+ __func__,
+ "delegate_class->parent == mono_defaults.multicastdelegate_class");
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
if (mono_security_core_clr_enabled ()) {
- if (!mono_security_core_clr_ensure_delegate_creation (method, throwOnBindFailure))
+ if (!mono_security_core_clr_ensure_delegate_creation (method, &error)) {
+ if (throwOnBindFailure)
+ mono_error_set_pending_exception (&error);
+ else
+ mono_error_cleanup (&error);
return NULL;
+ }
}
delegate = mono_object_new_checked (mono_object_domain (type), delegate_class, &error);
return NULL;
}
- tp->custom_type_info = (mono_object_isinst (this_obj, mono_defaults.iremotingtypeinfo_class) != NULL);
+ tp->custom_type_info = (mono_object_isinst_checked (this_obj, mono_defaults.iremotingtypeinfo_class, &error) != NULL);
+ if (!is_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
tp->remote_class = mono_remote_class (domain, class_name, klass, &error);
if (!is_ok (&error)) {
mono_error_set_pending_exception (&error);
ICALL_EXPORT MonoObject*
mono_TypedReference_ToObject (MonoTypedRef* tref)
{
+ MonoError error;
+ MonoObject *result = NULL;
if (MONO_TYPE_IS_REFERENCE (tref->type)) {
MonoObject** objp = (MonoObject **)tref->value;
return *objp;
}
- return mono_value_box (mono_domain_get (), tref->klass, tref->value);
+ result = mono_value_box_checked (mono_domain_get (), tref->klass, tref->value, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
ICALL_EXPORT MonoTypedRef
return message;
}
-ICALL_EXPORT int
-ves_icall_System_StackFrame_GetILOffsetFromFile (MonoString *path, guint32 method_token, guint32 method_index, int native_offset)
-{
- guint32 il_offset;
- char *path_str = mono_string_to_utf8 (path);
-
- if (!mono_seq_point_data_get_il_offset (path_str, method_token, method_index, native_offset, &il_offset))
- il_offset = -1;
-
- g_free (path_str);
-
- return il_offset;
-}
-
ICALL_EXPORT gpointer
ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcess (void)
{
/*
* Copyright 2015 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_IMAGE_INTERNALS_H__
#define __MONO_METADATA_IMAGE_INTERNALS_H__
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <stdio.h>
i = ((MonoImageLoader*)image->loader)->load_tables (image);
g_assert (image->heap_guid.data);
- g_assert (image->heap_guid.size >= 16);
- image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
+ if (!image->metadata_only) {
+ g_assert (image->heap_guid.size >= 16);
+
+ image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
+ } else {
+ /* PPDB files have no guid */
+ guint8 empty_guid [16];
+
+ memset (empty_guid, 0, sizeof (empty_guid));
+
+ image->guid = mono_guid_to_string (empty_guid);
+ }
return i;
}
goto done;
}
- if (image->loader == &pe_loader && !mono_verifier_verify_cli_data (image, &errors))
+ if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
goto invalid_image;
if (!mono_image_load_cli_data (image))
goto invalid_image;
- if (image->loader == &pe_loader && !mono_verifier_verify_table_data (image, &errors))
+ if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
goto invalid_image;
mono_image_load_names (image);
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*table_ptr = new_table;
mono_memory_barrier ();
domain->num_jit_info_tables++;
- mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
+ mono_thread_hazardous_try_free (table, (MonoHazardousFreeFunc)mono_jit_info_table_free);
table = new_table;
goto restart;
if (domain->num_jit_info_tables <= 1) {
/* Can it actually happen that we only have one table
but ji is still hazardous? */
- mono_thread_hazardous_free_or_queue (ji, g_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
+ mono_thread_hazardous_try_free (ji, g_free);
} else {
domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
}
* TODO:
* This should keep track of the assembly versions that we are loading.
*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <glib.h>
MonoClass *handle_class;
*retklass = NULL;
- result = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context);
+ MonoError inner_error;
+ result = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, &inner_error);
+ mono_error_cleanup (&inner_error);
// This checks the memberref type as well
if (!result || handle_class != mono_defaults.fieldhandle_class) {
mono_error_set_bad_image (error, image, "Bad field token 0x%08x", token);
static MonoMethodHeader*
inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context, MonoError *error)
{
- MonoMethodHeader *res;
- int i;
- res = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + sizeof (gpointer) * header->num_locals);
+ size_t locals_size = sizeof (gpointer) * header->num_locals;
+ size_t clauses_size = header->num_clauses * sizeof (MonoExceptionClause);
+ size_t header_size = MONO_SIZEOF_METHOD_HEADER + locals_size + clauses_size;
+ MonoMethodHeader *res = (MonoMethodHeader *)g_malloc0 (header_size);
+ res->num_locals = header->num_locals;
+ res->clauses = (MonoExceptionClause *) &res->locals [res->num_locals] ;
+ memcpy (res->clauses, header->clauses, clauses_size);
+
res->code = header->code;
res->code_size = header->code_size;
res->max_stack = header->max_stack;
res->num_clauses = header->num_clauses;
res->init_locals = header->init_locals;
- res->num_locals = header->num_locals;
- res->clauses = header->clauses;
+
+ res->is_transient = TRUE;
mono_error_init (error);
- for (i = 0; i < header->num_locals; ++i) {
+ for (int i = 0; i < header->num_locals; ++i) {
res->locals [i] = mono_class_inflate_generic_type_checked (header->locals [i], context, error);
if (!is_ok (error))
goto fail;
}
if (res->num_clauses) {
- res->clauses = (MonoExceptionClause *)g_memdup (header->clauses, sizeof (MonoExceptionClause) * res->num_clauses);
- for (i = 0; i < header->num_clauses; ++i) {
+ for (int i = 0; i < header->num_clauses; ++i) {
MonoExceptionClause *clause = &res->clauses [i];
if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
continue;
if (image_is_dynamic (image)) {
MonoClass *handle_class;
- result = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context);
+ result = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, error);
+ mono_error_assert_ok (error);
mono_loader_assert_no_error ();
// This checks the memberref type as well
return NULL;
}
- mono_image_lock (img);
-
- if (imethod->header) {
- mono_metadata_free_mh (iheader);
- mono_image_unlock (img);
- return imethod->header;
- }
-
- mono_memory_barrier ();
- imethod->header = iheader;
-
- mono_image_unlock (img);
-
- return imethod->header;
+ return iheader;
}
if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* (C) 2003 PT Cakram Datalingga Duaribu http://www.cdl2000.com
* Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
}
static void
-register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
+register_icall (gpointer func, const char *name, const char *sigstr, gboolean no_wrapper)
{
MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
- mono_register_jit_icall (func, name, sig, save);
+ mono_register_jit_icall (func, name, sig, no_wrapper);
}
MonoMethodSignature*
mono_native_tls_alloc (&load_type_info_tls_id, NULL);
}
+static MonoObject*
+mono_object_isinst_icall (MonoObject *obj, MonoClass *klass)
+{
+ MonoError error;
+ MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
void
mono_marshal_init (void)
{
register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
register_icall (g_free, "g_free", "void ptr", FALSE);
- register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
+ register_icall (mono_object_isinst_icall, "mono_object_isinst_icall", "object object ptr", FALSE);
register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
if (delegate->method_is_virtual)
method = mono_object_get_virtual_method (delegate->target, method);
- if (mono_method_signature (method)->pinvoke) {
+ if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
const char *exc_class, *exc_arg;
gpointer ftnptr;
if (use_aot_wrappers) {
wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
- this_obj = mono_value_box (mono_domain_get (), mono_defaults.int_class, &ftn);
+ this_obj = mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, &error);
+ if (!is_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return NULL;
+ }
} else {
memset (&piinfo, 0, sizeof (piinfo));
parse_unmanaged_function_pointer_attr (klass, &piinfo);
}
default: {
- char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
- MonoException *exc = mono_get_exception_not_implemented (msg);
- g_warning ("%s", msg);
- g_free (msg);
- mono_raise_exception (exc);
+ g_error ("marshalling conversion %d not implemented", conv);
}
}
}
method = mono_get_delegate_invoke (klass);
g_assert (method);
- return mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params);
+ MonoAsyncResult *result = mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
#ifndef DISABLE_JIT
EmitMarshalContext m;
g_assert (method != NULL);
- g_assert (!mono_method_signature (method)->pinvoke);
+ g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
/*
* FIXME: Should cache the method+delegate type pair, since the same method
static MonoObject *
mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
{
- MonoObject *isinst = mono_object_isinst (obj, klass);
+ MonoError error;
+ MonoObject *isinst = mono_object_isinst_checked (obj, klass, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
#ifndef DISABLE_REMOTING
if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
/*if (mono_object_isinst (value, aklass)) */
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
/* do_store: */
/*if (mono_object_isinst (value, aklass)) */
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
/* if (vklass->idepth < aklass->idepth) goto failue */
mono_mb_emit_ldarg (mb, 2);
mono_mb_emit_ldloc (mb, aklass);
- mono_mb_emit_icall (mb, mono_object_isinst);
+ mono_mb_emit_icall (mb, mono_object_isinst_icall);
b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc. (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
+#include <stdio.h>
+
#include "config.h"
+#include <mono/metadata/abi-details.h>
+
+#include <mono/metadata/class-internals.h>
+#include <mono/metadata/object-internals.h>
+#include <mono/metadata/monitor.h>
+#ifdef HAVE_SGEN_GC
+#include <mono/sgen/sgen-gc.h>
+#endif
+
+static int
+dump_arch (void)
+{
+#if defined (TARGET_X86)
+ g_print ("#ifdef TARGET_X86\n");
+#elif defined (TARGET_AMD64)
+ g_print ("#ifdef TARGET_AMD64\n");
+#elif defined (TARGET_ARM)
+ g_print ("#ifdef TARGET_ARM\n");
+#elif defined (TARGET_ARM64)
+ g_print ("#ifdef TARGET_ARM64\n");
+#else
+ return 0;
+#endif
+ return 1;
+}
+
+static int
+dump_os (void)
+{
+#if defined (PLATFORM_WIN32)
+ g_print ("#ifdef TARGET_WIN32\n");
+#elif defined (PLATFORM_ANDROID)
+ g_print ("#ifdef TARGET_ANDROID\n");
+#elif defined (PLATFORM_MACOSX)
+ g_print ("#ifdef TARGET_OSX\n");
+#elif defined (PLATFORM_IOS)
+ g_print ("#ifdef TARGET_IOS\n");
+#else
+ return 0;
+#endif
+ return 1;
+}
+
+void
+mono_dump_metadata_offsets (void);
+
+void
+mono_dump_metadata_offsets (void)
+{
+#ifdef USED_CROSS_COMPILER_OFFSETS
+ g_print ("not using native offsets\n");
+#else
+ g_print ("#ifndef USED_CROSS_COMPILER_OFFSETS\n");
+
+ if (!dump_arch ()) {
+ g_print ("#error failed to figure out the current arch\n");
+ return;
+ }
+
+ if (!dump_os ()) {
+ g_print ("#error failed to figure out the current OS\n");
+ return;
+ }
+
+#ifdef HAVE_SGEN_GC
+ g_print ("#ifndef HAVE_BOEHM_GC\n");
+#elif HAVE_BOEHM_GC
+ g_print ("#ifndef HAVE_SGEN_GC\n");
+#else
+ g_print ("#error no gc conf not supported\n");
+ return;
+#endif
+
+ g_print ("#define HAS_CROSS_COMPILER_OFFSETS\n");
+ g_print ("#if defined (USE_CROSS_COMPILE_OFFSETS) || defined (MONO_CROSS_COMPILE)\n");
+ g_print ("#if !defined (DISABLE_METADATA_OFFSETS)\n");
+ g_print ("#define USED_CROSS_COMPILER_OFFSETS\n");
+
+#define DISABLE_JIT_OFFSETS
+#define DECL_OFFSET2(struct,field,offset) this_should_not_happen
+#define DECL_ALIGN2(type,size) this_should_not_happen
+
+#define DECL_OFFSET(struct,field) g_print ("DECL_OFFSET2(%s,%s,%d)\n", #struct, #field, (int)MONO_STRUCT_OFFSET (struct, field));
+#define DECL_ALIGN(type) g_print ("DECL_ALIGN2(%s,%d)\n", #type, (int)MONO_ABI_ALIGNOF (type));
+#define DECL_SIZE(type) g_print ("DECL_SIZE2(%s,%d)\n", #type, (int)MONO_ABI_SIZEOF (type));
+#include <mono/metadata/object-offsets.h>
+
+ g_print ("#endif //disable metadata check\n");
+ g_print ("#endif //gc check\n");
+#endif
+}
+
+void
+mono_metadata_cross_helpers_run (void);
+
+void
+mono_metadata_cross_helpers_run (void)
+{
+#if defined (HAS_CROSS_COMPILER_OFFSETS) && !defined (MONO_CROSS_COMPILE)
+ gboolean is_broken = FALSE;
+
+#define DISABLE_JIT_OFFSETS
+#define USE_CROSS_COMPILE_OFFSETS
+#define DECL_OFFSET(struct,field) this_should_not_happen_for_cross_fields
+#define DECL_OFFSET2(struct,field,offset) \
+ if ((int)G_STRUCT_OFFSET (struct, field) != offset) { \
+ g_print (#struct ":" #field " invalid struct offset %d (expected %d)\n", \
+ offset, \
+ (int)G_STRUCT_OFFSET (struct, field)); \
+ is_broken = TRUE; \
+ }
+#define DECL_ALIGN(type) this_should_not_happen_for_cross_align
+#define DECL_ALIGN2(name,size) \
+ if (MONO_ALIGN_ ## name != size) { \
+ g_print (#name ": invalid alignment %d (expected %d)\n", \
+ size, \
+ MONO_ALIGN_ ## name); \
+ is_broken = TRUE; \
+ }
+#define DECL_SIZE(type) this_should_not_happen_for_cross_size
+#define DECL_SIZE2(name,size) \
+ if (MONO_SIZEOF_ ## name != size) { \
+ g_print (#name ": invalid size %d (expected %d)\n", \
+ size, \
+ MONO_SIZEOF_ ## name); \
+ is_broken = TRUE; \
+ }
+
+#include <mono/metadata/object-offsets.h>
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/metadata/metadata-cross-helpers.c"
+ g_assert (!is_broken);
#endif
+}
* Mono Project (http://www.mono-project.com)
*
* Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <mono/metadata/object-internals.h>
#include <mono/metadata/verify.h>
*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
guint32 sig;
const char *ptr;
- if (image_is_dynamic (image))
- return (MonoMethodSignature *)mono_lookup_dynamic_token (image, token, NULL);
+ if (image_is_dynamic (image)) {
+ ret = (MonoMethodSignature *)mono_lookup_dynamic_token (image, token, NULL, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return ret;
+ }
g_assert (mono_metadata_token_table(token) == MONO_TABLE_STANDALONESIG);
static void
free_inflated_method (MonoMethodInflated *imethod)
{
- int i;
MonoMethod *method = (MonoMethod*)imethod;
if (method->signature)
mono_metadata_free_inflated_signature (method->signature);
- if (!((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))) {
- MonoMethodHeader *header = imethod->header;
-
- if (header) {
- /* Allocated in inflate_generic_header () */
- for (i = 0; i < header->num_locals; ++i)
- mono_metadata_free_type (header->locals [i]);
- g_free (header->clauses);
- g_free (header);
- }
- }
-
g_free (method);
}
return FALSE;
type->data.klass = mono_class_from_mono_type (etype);
+
+ if (transient)
+ mono_metadata_free_type (etype);
+
g_assert (type->data.klass); //This was previously a check for NULL, but mcfmt should never fail. It can return a borken MonoClass, but should return at least something.
break;
}
*
* Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
*
* Copyright 2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Rodrigo Kumpera (rkumpera@novell.com)
*
* Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Return the list of basic blocks of method. Return NULL on failure and set @error.
*/
MonoSimpleBasicBlock*
-mono_basic_block_split (MonoMethod *method, MonoError *error)
+mono_basic_block_split (MonoMethod *method, MonoError *error, MonoMethodHeader *header)
{
- MonoError inner_error;
MonoSimpleBasicBlock *bb, *root;
const unsigned char *start, *end;
- MonoMethodHeader *header = mono_method_get_header_checked (method, &inner_error);
-
- mono_error_init (error);
-
- if (!header) {
- mono_error_set_not_verifiable (error, method, "Could not decode header due to %s", mono_error_get_message (&inner_error));
- mono_error_cleanup (&inner_error);
- return NULL;
- }
start = header->code;
end = start + header->code_size;
dump_bb_list (bb, &root, g_strdup_printf("AFTER LIVENESS %s", mono_method_full_name (method, TRUE)));
#endif
- mono_metadata_free_mh (header);
return bb;
fail:
- mono_metadata_free_mh (header);
mono_basic_block_free (bb);
return NULL;
}
};
MonoSimpleBasicBlock*
-mono_basic_block_split (MonoMethod *method, MonoError *error);
+mono_basic_block_split (MonoMethod *method, MonoError *error, MonoMethodHeader *header);
void
mono_basic_block_free (MonoSimpleBasicBlock *bb);
* mono-config-dirs.c:
*
* Copyright 2015 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
*
* Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#include <glib.h>
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include "mono-endian.h"
* Paolo Molaro (lupus@xamarin.com)
*
* Copyright 2013 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_G_HASH_H__
* Paolo Molaro (lupus@ximian.com)
*
* Copyright 2006-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/metadata/mono-mlist.h"
*
* Copyright 2008-2009 Novell, Inc (http://www.novell.com)
* 2011 Xamarin, Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Sebastien Pouliot <sebastien@ximian.com>
*
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifdef HAVE_CONFIG_H
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Ludovic Henry (ludovic@xamarin.com)
*
* Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
//
#include "mono/utils/mono-tls.h"
#include "mono/utils/mono-coop-mutex.h"
-#if 1
-#ifdef __GNUC__
-#define mono_assert(expr) G_STMT_START{ \
- if (!(expr)) \
- { \
- MonoException *ex; \
- char *msg = g_strdup_printf ("file %s: line %d (%s): " \
- "assertion failed: (%s)", __FILE__, __LINE__, \
- __PRETTY_FUNCTION__, #expr); \
- ex = mono_get_exception_execution_engine (msg); \
- g_free (msg); \
- mono_raise_exception (ex); \
- }; }G_STMT_END
-
-#define mono_assert_not_reached() G_STMT_START{ \
- MonoException *ex; \
- char *msg = g_strdup_printf ("file %s: line %d (%s): " \
- "should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__); \
- ex = mono_get_exception_execution_engine (msg); \
- g_free (msg); \
- mono_raise_exception (ex); \
-}G_STMT_END
-#else /* not GNUC */
-#define mono_assert(expr) G_STMT_START{ \
- if (!(expr)) \
- { \
- MonoException *ex; \
- char *msg = g_strdup_printf ("file %s: line %d: " \
- "assertion failed: (%s)", __FILE__, __LINE__, \
- #expr); \
- ex = mono_get_exception_execution_engine (msg); \
- g_free (msg); \
- mono_raise_exception (ex); \
- }; }G_STMT_END
-
-#define mono_assert_not_reached() G_STMT_START{ \
- MonoException *ex; \
- char *msg = g_strdup_printf ("file %s: line %d): " \
- "should not be reached", __FILE__, __LINE__); \
- ex = mono_get_exception_execution_engine (msg); \
- g_free (msg); \
- mono_raise_exception (ex); \
-}G_STMT_END
-#endif
-#else
-#define mono_assert(expr) g_assert(expr)
-#define mono_assert_not_reached() g_assert_not_reached()
-#endif
-
/* Use this as MONO_CHECK_ARG_NULL (arg,expr,) in functions returning void */
#define MONO_CHECK_ARG(arg, expr, retval) G_STMT_START{ \
if (G_UNLIKELY (!(expr))) \
#define IS_MONOTYPE(obj) (!(obj) || (((MonoObject*)(obj))->vtable->klass->image == mono_defaults.corlib && ((MonoReflectionType*)(obj))->type != NULL))
-/*
- * Make sure the argument, which should be a System.Type is a System.MonoType object
- * or equivalent, and not an instance of
- * a user defined subclass of System.Type. This should be used in places were throwing
- * an exception is safe.
- */
-#define CHECK_MONOTYPE(obj) do { \
- if (!IS_MONOTYPE (obj)) \
- mono_raise_exception (mono_get_exception_not_supported ("User defined subclasses of System.Type are not yet supported")); \
- } while (0)
-
/* This should be used for accessing members of Type[] arrays */
#define mono_type_array_get(arr,index) monotype_cast (mono_array_get ((arr), gpointer, (index)))
MonoReflectionType* mono_reflection_create_runtime_class (MonoReflectionTypeBuilder *tb);
-void mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides);
+void mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides, MonoError *error);
void mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *m);
void mono_reflection_destroy_dynamic_method (MonoReflectionDynamicMethod *mb);
MonoClass*
mono_class_bind_generic_parameters (MonoClass *klass, int type_argc, MonoType **types, gboolean is_dynamic);
MonoType*
-mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types);
+mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types, MonoError *error);
MonoReflectionMethod*
mono_reflection_bind_generic_method_parameters (MonoReflectionMethod *method, MonoArray *types);
void
MonoReflectionMarshalAsAttribute* mono_reflection_marshal_as_attribute_from_marshal_spec (MonoDomain *domain, MonoClass *klass, MonoMarshalSpec *spec, MonoError *error);
gpointer
-mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context);
+mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error);
gboolean
-mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass);
+mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass, MonoError *error);
gboolean
mono_reflection_is_valid_dynamic_token (MonoDynamicImage *image, guint32 token);
void
mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass);
+MonoObject *
+mono_value_box_checked (MonoDomain *domain, MonoClass *klass, void* val, MonoError *error);
+
MonoObject*
-mono_nullable_box (guint8 *buf, MonoClass *klass);
+mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error);
#ifdef MONO_SMALL_CONFIG
#define MONO_IMT_SIZE 9
void
mono_error_raise_exception (MonoError *target_error);
-void
+gboolean
mono_error_set_pending_exception (MonoError *error);
MonoArray *
MonoObject *
mono_object_clone_checked (MonoObject *obj, MonoError *error);
+MonoObject *
+mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error);
+
+MonoObject *
+mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error);
+
MonoString *
mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error);
HAS_CROSS_COMPILER_OFFSETS - if set, it means we found some cross offsets, it doesnt mean we'll use it.
USED_CROSS_COMPILER_OFFSETS - if set, it means we used the cross offsets
+
+Environment defines (from config.h and CFLAGS):
+
+MONO_GENERATING_OFFSETS - Set by an offsets generating tool to disable the usage of any (possibly non-existing) generated header.
+MONO_OFFSETS_FILE - Name of the header file containing the offsets to be used.
+
*/
#undef HAS_CROSS_COMPILER_OFFSETS
#undef USED_CROSS_COMPILER_OFFSETS
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/metadata/object-offsets.h"
+#if !defined (MONO_GENERATING_OFFSETS) && defined (MONO_OFFSETS_FILE)
+#include MONO_OFFSETS_FILE
#endif
-
#ifndef USED_CROSS_COMPILER_OFFSETS
DECL_ALIGN(gint8)
#if defined(TARGET_ARM)
DECL_OFFSET(MonoLMF, method)
+DECL_OFFSET(GSharedVtCallInfo, stack_usage)
+DECL_OFFSET(GSharedVtCallInfo, vret_arg_reg)
+DECL_OFFSET(GSharedVtCallInfo, ret_marshal)
+DECL_OFFSET(GSharedVtCallInfo, vret_slot)
+DECL_OFFSET(GSharedVtCallInfo, gsharedvt_in)
+#endif
+
+#if defined(TARGET_ARM64)
+DECL_OFFSET(GSharedVtCallInfo, stack_usage)
+DECL_OFFSET(GSharedVtCallInfo, gsharedvt_in)
+DECL_OFFSET(GSharedVtCallInfo, ret_marshal)
+DECL_OFFSET(GSharedVtCallInfo, vret_slot)
#endif
#if defined(TARGET_AMD64) || defined(TARGET_ARM64)
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2011 Novell, Inc (http://www.novell.com)
* Copyright 2001 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#ifdef HAVE_ALLOCA_H
klass = mono_class_from_mono_type (type);
if (mono_class_is_nullable (klass))
- return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
+ return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
o = mono_object_new_checked (domain, klass, error);
return_val_if_nok (error, NULL);
* mono_nullable_box:
* @buf: The buffer representing the data to be boxed
* @klass: the type to box it as.
+ * @error: set on oerr
*
* Creates a boxed vtype or NULL from the Nullable structure pointed to by
- * @buf.
+ * @buf. On failure returns NULL and sets @error
*/
MonoObject*
-mono_nullable_box (guint8 *buf, MonoClass *klass)
+mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;
- MonoError error;
-
+ mono_error_init (error);
MonoClass *param_class = klass->cast_class;
mono_class_setup_fields_locking (klass);
g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
- MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
+ return_val_if_nok (error, NULL);
if (param_class->has_references)
mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
else
* boxed object in the arg array with the copy.
*/
MonoObject *orig = mono_array_get (params, MonoObject*, i);
- MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
+ MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
mono_array_setref (params, i, copy);
}
if (!params)
return NULL;
- else
- return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
+ else {
+ MonoObject *result = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return result;
+ }
}
if (!obj) {
else
o = obj;
} else if (method->klass->valuetype) {
- obj = mono_value_box (mono_domain_get (), method->klass, obj);
+ obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
}
if (exc) {
nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
mono_error_raise_exception (&error); /* FIXME don't raise here */
- mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
+ MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
obj = mono_object_unbox (nullable);
}
im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
if (!im) {
- mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
+ mono_error_set_not_supported (error, "Linked away.");
return NULL;
}
vtable->domain->create_proxy_for_type_method = im;
MonoObject *
mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
{
- MONO_REQ_GC_UNSAFE_MODE;
-
MonoError error;
+ MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+/**
+ * mono_value_box_checked:
+ * @domain: the domain of the new object
+ * @class: the class of the value
+ * @value: a pointer to the unboxed data
+ * @error: set on error
+ *
+ * Returns: A newly created object which contains @value. On failure
+ * returns NULL and sets @error.
+ */
+MonoObject *
+mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
MonoObject *res;
int size;
MonoVTable *vtable;
+ mono_error_init (error);
+
g_assert (klass->valuetype);
if (mono_class_is_nullable (klass))
- return mono_nullable_box ((guint8 *)value, klass);
+ return mono_nullable_box ((guint8 *)value, klass, error);
vtable = mono_class_vtable (domain, klass);
if (!vtable)
return NULL;
size = mono_class_instance_size (klass);
- res = mono_object_new_alloc_specific_checked (vtable, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ res = mono_object_new_alloc_specific_checked (vtable, error);
+ return_val_if_nok (error, NULL);
size = size - sizeof (MonoObject);
#endif
#endif
if (klass->has_finalize) {
- mono_object_register_finalizer (res, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_object_register_finalizer (res, error);
+ return_val_if_nok (error, NULL);
}
return res;
}
* @obj: an object
* @klass: a pointer to a class
*
- * Returns: @obj if @obj is derived from @klass
+ * Returns: @obj if @obj is derived from @klass or NULL otherwise.
*/
MonoObject *
mono_object_isinst (MonoObject *obj, MonoClass *klass)
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
+ MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
+ mono_error_cleanup (&error);
+ return result;
+}
+
+
+/**
+ * mono_object_isinst_checked:
+ * @obj: an object
+ * @klass: a pointer to a class
+ * @error: set on error
+ *
+ * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
+ * On failure returns NULL and sets @error.
+ */
+MonoObject *
+mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ mono_error_init (error);
+
+ MonoObject *result = NULL;
+
if (!klass->inited)
mono_class_init (klass);
- if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
- return mono_object_isinst_mbyref (obj, klass);
+ if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ result = mono_object_isinst_mbyref_checked (obj, klass, error);
+ return result;
+ }
if (!obj)
return NULL;
MONO_REQ_GC_UNSAFE_MODE;
MonoError error;
+ MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
+ mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
+ return result;
+}
+
+MonoObject *
+mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
MonoVTable *vt;
+ mono_error_init (error);
+
if (!obj)
return NULL;
im = mono_object_get_virtual_method (rp, im);
g_assert (im);
- pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
+ return_val_if_nok (error, NULL);
pa [1] = obj;
- res = mono_runtime_invoke_checked (im, rp, pa, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ res = mono_runtime_invoke_checked (im, rp, pa, error);
+ return_val_if_nok (error, NULL);
if (*(MonoBoolean *) mono_object_unbox(res)) {
/* Update the vtable of the remote type, so it can safely cast to this new type */
* @obj: an object
* @klass: a pointer to a class
*
- * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
+ * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
*/
MonoObject *
mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
if (!obj) return NULL;
- if (mono_object_isinst_mbyref (obj, klass)) return obj;
-
- mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
- "System",
- "InvalidCastException"));
+ if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
+ mono_error_cleanup (&error);
return NULL;
}
mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
{
MONO_REQ_GC_UNSAFE_MODE;
+ MonoError error;
if (image->dynamic) {
- MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
+ MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
return str;
} else {
if (!mono_verifier_verify_string_signature (image, idx, NULL))
if (!im) {
im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
if (!im) {
- mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
+ mono_error_set_not_supported (error, "Linked away.");
return NULL;
}
real_proxy->vtable->domain->private_invoke_method = im;
klass = mono_class_from_mono_type (sig->params [i]);
- if (klass->valuetype)
- arg = mono_value_box (domain, klass, vpos);
- else
+ if (klass->valuetype) {
+ arg = mono_value_box_checked (domain, klass, vpos, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ } else
arg = *((MonoObject **)vpos);
mono_array_setref (msg->args, i, arg);
mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
}
- if (field_class->valuetype)
- arg = mono_value_box (domain, field_class, val);
- else
+ if (field_class->valuetype) {
+ arg = mono_value_box_checked (domain, field_class, val, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ } else
arg = *((MonoObject **)val);
MONO_API MonoString *
mono_object_to_string (MonoObject *obj, MonoObject **exc);
+MONO_RT_EXTERNAL_ONLY
MONO_API MonoObject *
mono_value_box (MonoDomain *domain, MonoClass *klass, void* val);
MONO_API MonoObject *
mono_object_clone (MonoObject *obj);
+MONO_RT_EXTERNAL_ONLY
MONO_API MonoObject *
mono_object_isinst (MonoObject *obj, MonoClass *klass);
+MONO_RT_EXTERNAL_ONLY
MONO_API MonoObject *
mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass);
+MONO_RT_EXTERNAL_ONLY
MONO_API MonoObject *
mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass);
*
* Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <mono/metadata/opcodes.h>
#include <stddef.h> /* for NULL */
*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <stdio.h>
*
* Copyright 2002 Ximian, Inc.
* Copyright 2002-2006 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com).
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <glib.h>
*
* (C) 2001 Ximian, Inc.
* Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _MONO_METADATA_RAND_H_
/*
* Copyright 2014 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_REFLECTION_INTERNALS_H__
#define __MONO_METADATA_REFLECTION_INTERNALS_H__
MonoArray*
mono_reflection_get_custom_attrs_data_checked (MonoObject *obj, MonoError *error);
+MonoArray*
+mono_reflection_get_custom_attrs_blob_checked (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues, MonoError *error);
+
MonoCustomAttrInfo*
mono_custom_attrs_from_index_checked (MonoImage *image, uint32_t idx, MonoError *error);
MonoCustomAttrInfo*
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Rodrigo Kumpera
*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include "mono/utils/mono-digest.h"
static guint32 mono_image_get_ctorbuilder_token (MonoDynamicImage *assembly, MonoReflectionCtorBuilder *cb, MonoError *error);
static guint32 mono_image_get_sighelper_token (MonoDynamicImage *assembly, MonoReflectionSigHelper *helper, MonoError *error);
static gboolean ensure_runtime_vtable (MonoClass *klass, MonoError *error);
-static gpointer resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context);
+static gpointer resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context, MonoError *error);
static guint32 mono_image_get_methodref_token_for_methodbuilder (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *method, MonoError *error);
static guint32 encode_generic_method_sig (MonoDynamicImage *assembly, MonoGenericContext *context);
static gpointer register_assembly (MonoDomain *domain, MonoReflectionAssembly *res, MonoAssembly *assembly);
static gboolean is_sre_method_on_tb_inst (MonoClass *klass);
static gboolean is_sre_ctor_on_tb_inst (MonoClass *klass);
+static gboolean type_is_reference (MonoType *type);
+
static guint32 mono_image_get_methodspec_token (MonoDynamicImage *assembly, MonoMethod *method);
static guint32 mono_image_get_inflated_method_token (MonoDynamicImage *assembly, MonoMethod *m);
static MonoMethod * inflate_method (MonoReflectionType *type, MonoObject *obj, MonoError *error);
/* Check for user defined reflection objects */
/* TypeDelegator is the only corlib type which doesn't look like a MonoReflectionType */
if (klass->image != mono_defaults.corlib || (strcmp (klass->name, "TypeDelegator") == 0)) {
- mono_error_set_generic_error (error, "System", "NotSupportedException", "User defined subclasses of System.Type are not yet supported");
+ mono_error_set_not_supported (error, "User defined subclasses of System.Type are not yet supported");
return 0;
}
{
MonoError error;
MonoReflectionMethodBody *result = mono_method_body_get_object_checked (domain, method, &error);
- mono_error_cleanup (&error); /* FIXME new API that doesn't swallow the error */
+ mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
return result;
}
/* for compatibility with .net */
if (method_is_dynamic (method)) {
- mono_error_set_exception_instance (error, mono_get_exception_invalid_operation (NULL));
+ mono_error_set_generic_error (error, "System", "InvalidOperationException", "");
return NULL;
}
local_var_sig_token = 0; //FIXME
ret = (MonoReflectionMethodBody*)mono_object_new_checked (domain, mono_class_get_method_body_class (), error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
ret->init_locals = header->init_locals;
ret->max_stack = header->max_stack;
MONO_OBJECT_SETREF (ret, locals, mono_array_new_cached (domain, mono_class_get_local_variable_info_class (), header->num_locals));
for (i = 0; i < header->num_locals; ++i) {
MonoReflectionLocalVariableInfo *info = (MonoReflectionLocalVariableInfo*)mono_object_new_checked (domain, mono_class_get_local_variable_info_class (), error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
rt = mono_type_get_object_checked (domain, header->locals [i], error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
MONO_OBJECT_SETREF (info, local_type, rt);
MONO_OBJECT_SETREF (ret, clauses, mono_array_new_cached (domain, mono_class_get_exception_handling_clause_class (), header->num_clauses));
for (i = 0; i < header->num_clauses; ++i) {
MonoReflectionExceptionHandlingClause *info = (MonoReflectionExceptionHandlingClause*)mono_object_new_checked (domain, mono_class_get_exception_handling_clause_class (), error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
MonoExceptionClause *clause = &header->clauses [i];
info->flags = clause->flags;
info->filter_offset = clause->data.filter_offset;
else if (clause->data.catch_class) {
rt = mono_type_get_object_checked (mono_domain_get (), &clause->data.catch_class->byval_arg, error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
MONO_OBJECT_SETREF (info, catch_type, rt);
}
mono_metadata_free_mh (header);
CACHE_OBJECT (MonoReflectionMethodBody *, method, ret, NULL);
return ret;
+
+fail:
+ mono_metadata_free_mh (header);
+ return NULL;
}
/**
return NULL;
instance = mono_reflection_bind_generic_parameters (
- the_type, info->type_arguments->len, type_args);
+ the_type, info->type_arguments->len, type_args, error);
g_free (type_args);
if (!instance)
} else if (strcmp (klass->name, "Assembly") == 0 || strcmp (klass->name, "MonoAssembly") == 0) {
token = mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1);
} else {
- mono_error_set_generic_error (error, "System", "NotImplementedException",
- "MetadataToken is not supported for type '%s.%s'", klass->name_space, klass->name);
+ mono_error_set_not_implemented (error, "MetadataToken is not supported for type '%s.%s'",
+ klass->name_space, klass->name);
return 0;
}
return NULL;
}
+static MonoObject*
+load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char** end, MonoError *error)
+{
+ mono_error_init (error);
+
+ gboolean is_ref = type_is_reference (t);
+
+ void *val = load_cattr_value (image, t, p, end, error);
+ if (!is_ok (error)) {
+ if (is_ref)
+ g_free (val);
+ return NULL;
+ }
+
+ if (is_ref)
+ return (MonoObject*)val;
+
+ MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type (t), val, error);
+ g_free (val);
+ return boxed;
+}
+
static MonoObject*
create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
{
p += 2;
for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
MonoObject *obj;
- void *val;
-
- val = load_cattr_value (image, mono_method_signature (method)->params [i], p, &p, error);
- if (!mono_error_ok (error)) {
- if (!type_is_reference (mono_method_signature (method)->params [i]))
- g_free (val);
- return;
- }
- obj = (MonoObject *)(type_is_reference (mono_method_signature (method)->params [i]) ?
- val : mono_value_box (domain, mono_class_from_mono_type (mono_method_signature (method)->params [i]), val));
+ obj = load_cattr_value_boxed (domain, image, mono_method_signature (method)->params [i], p, &p, error);
+ return_if_nok (error);
mono_array_setref (typedargs, i, obj);
-
- if (!type_is_reference (mono_method_signature (method)->params [i]))
- g_free (val);
}
named = p;
if (named_type == 0x53) {
MonoObject *obj;
MonoClassField *field = mono_class_get_field_from_name (attrklass, name);
- void *val;
if (!field) {
g_free (name);
arginfo [j].type = field->type;
arginfo [j].field = field;
- val = load_cattr_value (image, field->type, named, &named, error);
- if (!mono_error_ok (error)) {
- if (!type_is_reference (field->type))
- g_free (val);
+ obj = load_cattr_value_boxed (domain, image, field->type, named, &named, error);
+ if (!is_ok (error)) {
g_free (name);
return;
}
-
- obj = (MonoObject *)(type_is_reference (field->type) ? val : mono_value_box (domain, mono_class_from_mono_type (field->type), val));
mono_array_setref (namedargs, j, obj);
- if (!type_is_reference (field->type))
- g_free (val);
+
} else if (named_type == 0x54) {
MonoObject *obj;
MonoType *prop_type;
MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
- void *val;
if (!prop || !prop->set) {
g_free (name);
arginfo [j].type = prop_type;
arginfo [j].prop = prop;
- val = load_cattr_value (image, prop_type, named, &named, error);
- if (!mono_error_ok (error)) {
- if (!type_is_reference (prop_type))
- g_free (val);
+ obj = load_cattr_value_boxed (domain, image, prop_type, named, &named, error);
+ if (!is_ok (error)) {
g_free (name);
return;
}
-
- obj = (MonoObject *)(type_is_reference (prop_type) ? val : mono_value_box (domain, mono_class_from_mono_type (prop_type), val));
mono_array_setref (namedargs, j, obj);
- if (!type_is_reference (prop_type))
- g_free (val);
}
g_free (name);
}
#endif
else {
char *type_name = mono_type_get_full_name (member_class);
- mono_error_set_generic_error (error, "System", "NotSupportedException",
+ mono_error_set_not_supported (error,
"Custom attributes on a ParamInfo with member %s are not supported",
type_name);
g_free (type_name);
}
}
- res = mono_reflection_bind_generic_parameters (gclass->generic_type, count, types);
+ res = mono_reflection_bind_generic_parameters (gclass->generic_type, count, types, error);
g_free (types);
g_assert (res);
gclass->type.type = res;
mono_error_set_pending_exception (&error);
}
-void
-mono_reflection_register_with_runtime (MonoReflectionType *type)
+static gboolean
+reflection_register_with_runtime (MonoReflectionType *type, MonoError *error)
{
- MonoError error;
- MonoType *res = mono_reflection_type_get_handle (type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
MonoDomain *domain = mono_object_domain ((MonoObject*)type);
MonoClass *klass;
- if (!res)
- mono_raise_exception (mono_get_exception_argument (NULL, "Invalid generic instantiation, one or more arguments are not proper user types"));
+ mono_error_init (error);
+
+ MonoType *res = mono_reflection_type_get_handle (type, error);
+
+ if (!res && is_ok (error)) {
+ mono_error_set_argument (error, NULL, "Invalid generic instantiation, one or more arguments are not proper user types");
+ }
+ return_val_if_nok (error, FALSE);
klass = mono_class_from_mono_type (res);
}
mono_domain_unlock (domain);
mono_loader_unlock ();
+
+ return TRUE;
+}
+
+void
+mono_reflection_register_with_runtime (MonoReflectionType *type)
+{
+ MonoError error;
+ (void) reflection_register_with_runtime (type, &error);
+ mono_error_set_pending_exception (&error);
}
/**
* LOCKING: Assumes the loader lock is held.
*/
static MonoMethodSignature*
-parameters_to_signature (MonoImage *image, MonoArray *parameters) {
- MonoError error;
+parameters_to_signature (MonoImage *image, MonoArray *parameters, MonoError *error) {
MonoMethodSignature *sig;
int count, i;
+ mono_error_init (error);
+
count = parameters? mono_array_length (parameters): 0;
sig = (MonoMethodSignature *)image_g_malloc0 (image, MONO_SIZEOF_METHOD_SIGNATURE + sizeof (MonoType*) * count);
sig->param_count = count;
sig->sentinelpos = -1; /* FIXME */
for (i = 0; i < count; ++i) {
- sig->params [i] = mono_type_array_get_and_resolve (parameters, i, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ sig->params [i] = mono_type_array_get_and_resolve (parameters, i, error);
+ if (!is_ok (error)) {
+ image_g_free (image, sig);
+ return NULL;
+ }
}
return sig;
}
* LOCKING: Assumes the loader lock is held.
*/
static MonoMethodSignature*
-ctor_builder_to_signature (MonoImage *image, MonoReflectionCtorBuilder *ctor) {
+ctor_builder_to_signature (MonoImage *image, MonoReflectionCtorBuilder *ctor, MonoError *error) {
MonoMethodSignature *sig;
- sig = parameters_to_signature (image, ctor->parameters);
+ mono_error_init (error);
+
+ sig = parameters_to_signature (image, ctor->parameters, error);
+ return_val_if_nok (error, NULL);
sig->hasthis = ctor->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
sig->ret = &mono_defaults.void_class->byval_arg;
return sig;
* LOCKING: Assumes the loader lock is held.
*/
static MonoMethodSignature*
-method_builder_to_signature (MonoImage *image, MonoReflectionMethodBuilder *method) {
- MonoError error;
+method_builder_to_signature (MonoImage *image, MonoReflectionMethodBuilder *method, MonoError *error) {
MonoMethodSignature *sig;
- sig = parameters_to_signature (image, method->parameters);
+ mono_error_init (error);
+
+ sig = parameters_to_signature (image, method->parameters, error);
+ return_val_if_nok (error, NULL);
sig->hasthis = method->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
if (method->rtype) {
- sig->ret = mono_reflection_type_get_handle ((MonoReflectionType*)method->rtype, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ sig->ret = mono_reflection_type_get_handle ((MonoReflectionType*)method->rtype, error);
+ if (!is_ok (error)) {
+ image_g_free (image, sig);
+ return NULL;
+ }
} else {
sig->ret = &mono_defaults.void_class->byval_arg;
}
}
static MonoMethodSignature*
-dynamic_method_to_signature (MonoReflectionDynamicMethod *method) {
- MonoError error;
+dynamic_method_to_signature (MonoReflectionDynamicMethod *method, MonoError *error) {
MonoMethodSignature *sig;
- sig = parameters_to_signature (NULL, method->parameters);
+ mono_error_init (error);
+
+ sig = parameters_to_signature (NULL, method->parameters, error);
+ return_val_if_nok (error, NULL);
sig->hasthis = method->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
if (method->rtype) {
- sig->ret = mono_reflection_type_get_handle (method->rtype, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ sig->ret = mono_reflection_type_get_handle (method->rtype, error);
+ if (!is_ok (error)) {
+ g_free (sig);
+ return NULL;
+ }
} else {
sig->ret = &mono_defaults.void_class->byval_arg;
}
}
static void
-get_prop_name_and_type (MonoObject *prop, char **name, MonoType **type)
+get_prop_name_and_type (MonoObject *prop, char **name, MonoType **type, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
MonoClass *klass = mono_object_class (prop);
if (strcmp (klass->name, "PropertyBuilder") == 0) {
MonoReflectionPropertyBuilder *pb = (MonoReflectionPropertyBuilder *)prop;
*name = mono_string_to_utf8 (pb->name);
- *type = mono_reflection_type_get_handle ((MonoReflectionType*)pb->type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ *type = mono_reflection_type_get_handle ((MonoReflectionType*)pb->type, error);
} else {
MonoReflectionProperty *p = (MonoReflectionProperty *)prop;
*name = g_strdup (p->property->name);
}
static void
-get_field_name_and_type (MonoObject *field, char **name, MonoType **type)
+get_field_name_and_type (MonoObject *field, char **name, MonoType **type, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
MonoClass *klass = mono_object_class (field);
if (strcmp (klass->name, "FieldBuilder") == 0) {
MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)field;
*name = mono_string_to_utf8 (fb->name);
- *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
} else {
MonoReflectionField *f = (MonoReflectionField *)field;
*name = g_strdup (mono_field_get_name (f->field));
type = mono_reflection_type_get_underlying_system_type (type, error);
return_val_if_nok (error, NULL);
if (is_usertype (type)) {
- mono_error_set_generic_error (error, "System", "NotSupportedException", "User defined subclasses of System.Type are not yet supported22");
+ mono_error_set_not_supported (error, "User defined subclasses of System.Type are not yet supported22");
return NULL;
}
}
return type;
}
-/*
+/**
+ * encode_cattr_value:
* Encode a value in a custom attribute stream of bytes.
* The value to encode is either supplied as an object in argument val
* (valuetypes are boxed), or as a pointer to the data in the
* @buflen contains the size of the buffer and is used to return the new buffer size
* if this needs to be realloced.
* @retbuffer and @retp return the start and the position of the buffer
+ * @error set on error.
*/
static void
-encode_cattr_value (MonoAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, MonoObject *arg, char *argval)
+encode_cattr_value (MonoAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, MonoObject *arg, char *argval, MonoError *error)
{
- MonoError error;
MonoTypeEnum simple_type;
+ mono_error_init (error);
if ((p-buffer) + 10 >= *buflen) {
char *newbuf;
*buflen *= 2;
break;
}
handle_type:
- arg_type = mono_reflection_type_get_handle ((MonoReflectionType*)arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ arg_type = mono_reflection_type_get_handle ((MonoReflectionType*)arg, error);
+ return_if_nok (error);
+
str = type_get_qualified_name (arg_type, NULL);
slen = strlen (str);
if ((p-buffer) + 10 + slen >= *buflen) {
char *elptr = mono_array_addr ((MonoArray*)arg, char, 0);
int elsize = mono_class_array_element_size (arg_eclass);
for (i = 0; i < len; ++i) {
- encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &arg_eclass->byval_arg, NULL, elptr);
+ encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &arg_eclass->byval_arg, NULL, elptr, error);
+ return_if_nok (error);
elptr += elsize;
}
} else if (eclass->valuetype && arg_eclass->valuetype) {
char *elptr = mono_array_addr ((MonoArray*)arg, char, 0);
int elsize = mono_class_array_element_size (eclass);
for (i = 0; i < len; ++i) {
- encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, NULL, elptr);
+ encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, NULL, elptr, error);
+ return_if_nok (error);
elptr += elsize;
}
} else {
for (i = 0; i < len; ++i) {
- encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, mono_array_get ((MonoArray*)arg, MonoObject*, i), NULL);
+ encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, mono_array_get ((MonoArray*)arg, MonoObject*, i), NULL, error);
+ return_if_nok (error);
}
}
break;
klass = mono_object_class (arg);
- if (mono_object_isinst (arg, mono_defaults.systemtype_class)) {
+ if (mono_object_isinst_checked (arg, mono_defaults.systemtype_class, error)) {
*p++ = 0x50;
goto handle_type;
- } else if (klass->enumtype) {
+ } else {
+ return_if_nok (error);
+ }
+
+ if (klass->enumtype) {
*p++ = 0x55;
} else if (klass == mono_defaults.string_class) {
simple_type = MONO_TYPE_STRING;
*p++ = 0x51;
else
*p++ = klass->element_class->byval_arg.type;
- encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &klass->byval_arg, arg, NULL);
+ encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &klass->byval_arg, arg, NULL, error);
+ return_if_nok (error);
break;
} else if (klass->byval_arg.type >= MONO_TYPE_BOOLEAN && klass->byval_arg.type <= MONO_TYPE_R8) {
*p++ = simple_type = klass->byval_arg.type;
#ifndef DISABLE_REFLECTION_EMIT
static void
-encode_named_val (MonoReflectionAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, char *name, MonoObject *value)
+encode_named_val (MonoReflectionAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, char *name, MonoObject *value, MonoError *error)
{
int len;
+
+ mono_error_init (error);
+
/* Preallocate a large enough buffer */
if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
char *str = type_get_qualified_name (type, NULL);
mono_metadata_encode_value (len, p, &p);
memcpy (p, name, len);
p += len;
- encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, buflen, type, value, NULL);
+ encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, buflen, type, value, NULL, error);
+ return_if_nok (error);
*retp = p;
*retbuffer = buffer;
}
-/*
+/**
* mono_reflection_get_custom_attrs_blob:
* @ctor: custom attribute constructor
* @ctorArgs: arguments o the constructor
MonoArray*
mono_reflection_get_custom_attrs_blob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues)
{
- MonoArray *result;
+ MonoError error;
+ MonoArray *result = mono_reflection_get_custom_attrs_blob_checked (assembly, ctor, ctorArgs, properties, propValues, fields, fieldValues, &error);
+ mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
+ return result;
+}
+
+/**
+ * mono_reflection_get_custom_attrs_blob_checked:
+ * @ctor: custom attribute constructor
+ * @ctorArgs: arguments o the constructor
+ * @properties:
+ * @propValues:
+ * @fields:
+ * @fieldValues:
+ * @error: set on error
+ *
+ * Creates the blob of data that needs to be saved in the metadata and that represents
+ * the custom attributed described by @ctor, @ctorArgs etc.
+ * Returns: a Byte array representing the blob of data. On failure returns NULL and sets @error.
+ */
+MonoArray*
+mono_reflection_get_custom_attrs_blob_checked (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues, MonoError *error)
+{
+ MonoArray *result = NULL;
MonoMethodSignature *sig;
MonoObject *arg;
char *buffer, *p;
guint32 buflen, i;
+ mono_error_init (error);
+
if (strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
/* sig is freed later so allocate it in the heap */
- sig = ctor_builder_to_signature (NULL, (MonoReflectionCtorBuilder*)ctor);
+ sig = ctor_builder_to_signature (NULL, (MonoReflectionCtorBuilder*)ctor, error);
+ if (!is_ok (error)) {
+ g_free (sig);
+ return NULL;
+ }
} else {
sig = mono_method_signature (((MonoReflectionMethod*)ctor)->method);
}
*p++ = 0;
for (i = 0; i < sig->param_count; ++i) {
arg = mono_array_get (ctorArgs, MonoObject*, i);
- encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, &buflen, sig->params [i], arg, NULL);
+ encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, &buflen, sig->params [i], arg, NULL, error);
+ if (!is_ok (error)) goto leave;
}
i = 0;
if (properties)
char *pname;
prop = (MonoObject *)mono_array_get (properties, gpointer, i);
- get_prop_name_and_type (prop, &pname, &ptype);
+ get_prop_name_and_type (prop, &pname, &ptype, error);
+ if (!is_ok (error)) goto leave;
*p++ = 0x54; /* PROPERTY signature */
- encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ptype, pname, (MonoObject*)mono_array_get (propValues, gpointer, i));
+ encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ptype, pname, (MonoObject*)mono_array_get (propValues, gpointer, i), error);
g_free (pname);
+ if (!is_ok (error)) goto leave;
}
}
char *fname;
field = (MonoObject *)mono_array_get (fields, gpointer, i);
- get_field_name_and_type (field, &fname, &ftype);
+ get_field_name_and_type (field, &fname, &ftype, error);
+ if (!is_ok (error)) goto leave;
*p++ = 0x53; /* FIELD signature */
- encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ftype, fname, (MonoObject*)mono_array_get (fieldValues, gpointer, i));
+ encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ftype, fname, (MonoObject*)mono_array_get (fieldValues, gpointer, i), error);
g_free (fname);
+ if (!is_ok (error)) goto leave;
}
}
result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
p = mono_array_addr (result, char, 0);
memcpy (p, buffer, buflen);
+leave:
g_free (buffer);
if (strcmp (ctor->vtable->klass->name, "MonoCMethod"))
g_free (sig);
return result;
}
-/*
- * mono_reflection_setup_internal_class:
+/**
+ * reflection_setup_internal_class:
* @tb: a TypeBuilder object
+ * @error: set on error
*
* Creates a MonoClass that represents the TypeBuilder.
* This is a trick that lets us simplify a lot of reflection code
* (and will allow us to support Build and Run assemblies easier).
+ *
+ * Returns TRUE on success. On failure, returns FALSE and sets @error.
*/
-void
-mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
+static gboolean
+reflection_setup_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error)
{
- MonoError error;
MonoClass *klass, *parent;
- RESOLVE_TYPE (tb->parent, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_init (error);
+ RESOLVE_TYPE (tb->parent, error);
+ return_val_if_nok (error, FALSE);
mono_loader_lock ();
if (tb->parent) {
- MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, &error);
- if (!is_ok (&error)) {
+ MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
+ if (!is_ok (error)) {
mono_loader_unlock ();
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return FALSE;
}
/* check so we can compile corlib correctly */
if (strcmp (mono_object_class (tb->parent)->name, "TypeBuilder") == 0) {
mono_class_setup_parent (klass, parent);
mono_class_setup_mono_type (klass);
mono_loader_unlock ();
- return;
+ return TRUE;
}
klass = (MonoClass *)mono_image_alloc0 (&tb->module->dynamic_image->image, sizeof (MonoClass));
klass->image = &tb->module->dynamic_image->image;
klass->inited = 1; /* we lie to the runtime */
- klass->name = mono_string_to_utf8_image (klass->image, tb->name, &error);
- if (!mono_error_ok (&error))
+ klass->name = mono_string_to_utf8_image (klass->image, tb->name, error);
+ if (!is_ok (error))
goto failure;
- klass->name_space = mono_string_to_utf8_image (klass->image, tb->nspace, &error);
- if (!mono_error_ok (&error))
+ klass->name_space = mono_string_to_utf8_image (klass->image, tb->nspace, error);
+ if (!is_ok (error))
goto failure;
klass->type_token = MONO_TOKEN_TYPE_DEF | tb->table_idx;
klass->flags = tb->attrs;
if (tb->nesting_type) {
g_assert (tb->nesting_type->type);
- MonoType *nesting_type = mono_reflection_type_get_handle (tb->nesting_type, &error);
- if (!is_ok (&error)) goto failure;
+ MonoType *nesting_type = mono_reflection_type_get_handle (tb->nesting_type, error);
+ if (!is_ok (error)) goto failure;
klass->nested_in = mono_class_from_mono_type (nesting_type);
}
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
mono_loader_unlock ();
- return;
+ return TRUE;
failure:
mono_loader_unlock ();
- mono_error_raise_exception (&error);
+ return FALSE;
+}
+
+/**
+ * mono_reflection_setup_internal_class:
+ * @tb: a TypeBuilder object
+ *
+ * (icall)
+ * Creates a MonoClass that represents the TypeBuilder.
+ * This is a trick that lets us simplify a lot of reflection code
+ * (and will allow us to support Build and Run assemblies easier).
+ *
+ */
+void
+mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
+{
+ MonoError error;
+ (void) reflection_setup_internal_class (tb, &error);
+ mono_error_set_pending_exception (&error);
}
/*
klass->generic_container->context.class_inst = mono_get_shared_generic_inst (klass->generic_container);
}
-/*
- * mono_reflection_create_internal_class:
+/**
+ * reflection_create_internal_class:
* @tb: a TypeBuilder object
+ * @error: set on error
*
* Actually create the MonoClass that is associated with the TypeBuilder.
+ * On success returns TRUE, on failure returns FALSE and sets @error.
+ *
*/
-void
-mono_reflection_create_internal_class (MonoReflectionTypeBuilder *tb)
+static gboolean
+reflection_create_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error)
{
- MonoError error;
+
MonoClass *klass;
+ mono_error_init (error);
klass = mono_class_from_mono_type (tb->type.type);
mono_loader_lock ();
fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, 0);
- MonoType *field_type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- if (!is_ok (&error)) {
+ MonoType *field_type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
+ if (!is_ok (error)) {
mono_loader_unlock ();
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return FALSE;
}
if (!mono_type_is_valid_enum_basetype (field_type)) {
mono_loader_unlock ();
- return;
+ return TRUE;
}
- enum_basetype = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- if (!is_ok (&error)) {
+ enum_basetype = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
+ if (!is_ok (error)) {
mono_loader_unlock ();
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return FALSE;
}
klass->element_class = mono_class_from_mono_type (enum_basetype);
if (!klass->element_class)
mono_class_setup_vtable_general (klass, NULL, 0, NULL);
}
mono_loader_unlock ();
+ return TRUE;
+}
+
+/**
+ * mono_reflection_create_internal_class:
+ * @tb: a TypeBuilder object
+ *
+ * (icall)
+ * Actually create the MonoClass that is associated with the TypeBuilder.
+ */
+void
+mono_reflection_create_internal_class (MonoReflectionTypeBuilder *tb)
+{
+ MonoError error;
+ (void) reflection_create_internal_class (tb, &error);
+ mono_error_set_pending_exception (&error);
}
static MonoMarshalSpec*
mono_marshal_spec_from_builder (MonoImage *image, MonoAssembly *assembly,
- MonoReflectionMarshal *minfo)
+ MonoReflectionMarshal *minfo, MonoError *error)
{
- MonoError error;
MonoMarshalSpec *res;
+ mono_error_init (error);
+
res = image_g_new0 (image, MonoMarshalSpec, 1);
res->native = (MonoMarshalNative)minfo->type;
case MONO_NATIVE_CUSTOM:
if (minfo->marshaltyperef) {
- MonoType *marshaltyperef = mono_reflection_type_get_handle ((MonoReflectionType*)minfo->marshaltyperef, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *marshaltyperef = mono_reflection_type_get_handle ((MonoReflectionType*)minfo->marshaltyperef, error);
+ if (!is_ok (error)) {
+ image_g_free (image, res);
+ return NULL;
+ }
res->data.custom_data.custom_name =
type_get_fully_qualified_name (marshaltyperef);
}
if (specs == NULL)
specs = image_g_new0 (image, MonoMarshalSpec*, sig->param_count + 1);
specs [pb->position] =
- mono_marshal_spec_from_builder (image, klass->image->assembly, pb->marshal_info);
+ mono_marshal_spec_from_builder (image, klass->image->assembly, pb->marshal_info, &error);
+ if (!is_ok (&error)) {
+ mono_loader_unlock ();
+ image_g_free (image, specs);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ }
}
}
}
MonoMethodSignature *sig;
mono_loader_lock ();
- sig = ctor_builder_to_signature (klass->image, mb);
+ g_assert (klass->image != NULL);
+ sig = ctor_builder_to_signature (klass->image, mb, error);
mono_loader_unlock ();
+ return_val_if_nok (error, NULL);
if (!reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
return NULL;
mono_error_init (error);
mono_loader_lock ();
- sig = method_builder_to_signature (klass->image, mb);
+ g_assert (klass->image != NULL);
+ sig = method_builder_to_signature (klass->image, mb, error);
mono_loader_unlock ();
+ return_val_if_nok (error, NULL);
if (!reflection_methodbuilder_from_method_builder (&rmb, mb, error))
return NULL;
}
static MonoClassField*
-fieldbuilder_to_mono_class_field (MonoClass *klass, MonoReflectionFieldBuilder* fb)
+fieldbuilder_to_mono_class_field (MonoClass *klass, MonoReflectionFieldBuilder* fb, MonoError *error)
{
MonoClassField *field;
MonoType *custom;
- MonoError error;
+
+ mono_error_init (error);
field = g_new0 (MonoClassField, 1);
- field->name = mono_string_to_utf8_image (klass->image, fb->name, &error);
- g_assert (mono_error_ok (&error));
+ field->name = mono_string_to_utf8_image (klass->image, fb->name, error);
+ mono_error_assert_ok (error);
if (fb->attrs || fb->modreq || fb->modopt) {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- if (!is_ok (&error)) {
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
+ if (!is_ok (error)) {
g_free (field);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return NULL;
}
field->type = mono_metadata_type_dup (NULL, type);
field->type->attrs = fb->attrs;
g_assert (image_is_dynamic (klass->image));
- custom = add_custom_modifiers ((MonoDynamicImage*)klass->image, field->type, fb->modreq, fb->modopt, &error);
+ custom = add_custom_modifiers ((MonoDynamicImage*)klass->image, field->type, fb->modreq, fb->modopt, error);
g_free (field->type);
- if (!is_ok (&error)) {
+ if (!is_ok (error)) {
g_free (field);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return NULL;
}
field->type = mono_metadata_type_dup (klass->image, custom);
g_free (custom);
} else {
- field->type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- if (!is_ok (&error)) {
+ field->type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
+ if (!is_ok (error)) {
g_free (field);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return NULL;
}
}
if (fb->offset != -1)
}
#endif
+/**
+ * mono_reflection_bind_generic_parameters:
+ * @type: a managed type object (which should be some kind of generic (instance? definition?))
+ * @type_args: the number of type arguments to bind
+ * @types: array of type arguments
+ * @error: set on error
+ *
+ * Given a managed type object for a generic type instance, binds each of its arguments to the specified types.
+ * Returns the MonoType* for the resulting type instantiation. On failure returns NULL and sets @error.
+ */
MonoType*
-mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types)
+mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types, MonoError *error)
{
- MonoError error;
MonoClass *klass;
MonoReflectionTypeBuilder *tb = NULL;
gboolean is_dynamic = FALSE;
MonoClass *geninst;
+ mono_error_init (error);
+
mono_loader_lock ();
if (is_sre_type_builder (mono_object_class (type))) {
if (tb && tb->generic_container)
mono_reflection_create_generic_class (tb);
- MonoType *t = mono_reflection_type_get_handle (type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *t = mono_reflection_type_get_handle (type, error);
+ if (!is_ok (error)) {
+ mono_loader_unlock ();
+ return NULL;
+ }
klass = mono_class_from_mono_type (t);
if (!klass->generic_container) {
mono_loader_unlock ();
+ mono_error_set_type_load_class (error, klass, "Cannot bind generic parameters of a non-generic type");
return NULL;
}
}
/*TODO avoid saving custom attrs for generic classes as it's enough to have them on the generic type definition.*/
-void
-mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *fields)
+static gboolean
+reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *fields, MonoError *error)
{
- MonoError error;
MonoGenericClass *gclass;
MonoDynamicGenericClass *dgclass;
MonoClass *klass, *gklass;
MonoType *gtype;
int i;
- gtype = mono_reflection_type_get_handle ((MonoReflectionType*)type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_init (error);
+
+ gtype = mono_reflection_type_get_handle ((MonoReflectionType*)type, error);
+ return_val_if_nok (error, FALSE);
klass = mono_class_from_mono_type (gtype);
g_assert (gtype->type == MONO_TYPE_GENERICINST);
gclass = gtype->data.generic_class;
if (!gclass->is_dynamic)
- return;
+ return TRUE;
dgclass = (MonoDynamicGenericClass *) gclass;
if (dgclass->initialized)
- return;
+ return TRUE;
gklass = gclass->container_class;
mono_class_init (gklass);
dgclass->field_generic_types = mono_image_set_new0 (gclass->owner, MonoType*, dgclass->count_fields);
for (i = 0; i < dgclass->count_fields; i++) {
- MonoError error;
MonoObject *obj = (MonoObject *)mono_array_get (fields, gpointer, i);
MonoClassField *field, *inflated_field = NULL;
- if (!strcmp (obj->vtable->klass->name, "FieldBuilder"))
- inflated_field = field = fieldbuilder_to_mono_class_field (klass, (MonoReflectionFieldBuilder *) obj);
- else if (!strcmp (obj->vtable->klass->name, "MonoField"))
+ if (!strcmp (obj->vtable->klass->name, "FieldBuilder")) {
+ inflated_field = field = fieldbuilder_to_mono_class_field (klass, (MonoReflectionFieldBuilder *) obj, error);
+ return_val_if_nok (error, FALSE);
+ } else if (!strcmp (obj->vtable->klass->name, "MonoField"))
field = ((MonoReflectionField *) obj)->field;
else {
field = NULL; /* prevent compiler warning */
dgclass->fields [i] = *field;
dgclass->fields [i].parent = klass;
dgclass->fields [i].type = mono_class_inflate_generic_type_checked (
- field->type, mono_generic_class_get_context ((MonoGenericClass *) dgclass), &error);
- mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+ field->type, mono_generic_class_get_context ((MonoGenericClass *) dgclass), error);
+ mono_error_assert_ok (error); /* FIXME don't swallow the error */
dgclass->field_generic_types [i] = field->type;
MONO_GC_REGISTER_ROOT_IF_MOVING (dgclass->field_objects [i], MONO_ROOT_SOURCE_REFLECTION, "dynamic generic class field object");
dgclass->field_objects [i] = obj;
}
dgclass->initialized = TRUE;
+ return TRUE;
+}
+
+void
+mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *fields)
+{
+ MonoError error;
+ (void) reflection_generic_class_initialize (type, fields, &error);
+ mono_error_set_pending_exception (&error);
}
void
}
}
-static void
-fix_partial_generic_class (MonoClass *klass)
+/**
+ * fix_partial_generic_class:
+ * @klass: a generic instantiation MonoClass
+ * @error: set on error
+ *
+ * Assumes that the generic container of @klass has its vtable
+ * initialized, and updates the parent class, insterfaces, methods and
+ * fields of @klass by inflating the types using the generic context.
+ *
+ * On success returns TRUE, on failure returns FALSE and sets @error.
+ *
+ */
+static gboolean
+fix_partial_generic_class (MonoClass *klass, MonoError *error)
{
MonoClass *gklass = klass->generic_class->container_class;
MonoDynamicGenericClass *dgclass;
int i;
+ mono_error_init (error);
+
if (klass->wastypebuilder)
- return;
+ return TRUE;
dgclass = (MonoDynamicGenericClass *) klass->generic_class;
if (klass->parent != gklass->parent) {
- MonoError error;
- MonoType *parent_type = mono_class_inflate_generic_type_checked (&gklass->parent->byval_arg, &klass->generic_class->context, &error);
- if (mono_error_ok (&error)) {
+ MonoType *parent_type = mono_class_inflate_generic_type_checked (&gklass->parent->byval_arg, &klass->generic_class->context, error);
+ if (mono_error_ok (error)) {
MonoClass *parent = mono_class_from_mono_type (parent_type);
mono_metadata_free_type (parent_type);
if (parent != klass->parent) {
mono_class_setup_parent (klass, parent);
}
} else {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- mono_error_cleanup (&error);
if (gklass->wastypebuilder)
klass->wastypebuilder = TRUE;
- return;
+ return FALSE;
}
}
if (!dgclass->initialized)
- return;
+ return TRUE;
if (klass->method.count != gklass->method.count) {
klass->method.count = gklass->method.count;
klass->methods = (MonoMethod **)mono_image_alloc (klass->image, sizeof (MonoMethod*) * (klass->method.count + 1));
for (i = 0; i < klass->method.count; i++) {
- MonoError error;
klass->methods [i] = mono_class_inflate_generic_method_full_checked (
- gklass->methods [i], klass, mono_class_get_context (klass), &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ gklass->methods [i], klass, mono_class_get_context (klass), error);
+ mono_error_assert_ok (error);
}
}
klass->interfaces_packed = NULL; /*make setup_interface_offsets happy*/
for (i = 0; i < gklass->interface_count; ++i) {
- MonoError error;
- MonoType *iface_type = mono_class_inflate_generic_type_checked (&gklass->interfaces [i]->byval_arg, mono_class_get_context (klass), &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *iface_type = mono_class_inflate_generic_type_checked (&gklass->interfaces [i]->byval_arg, mono_class_get_context (klass), error);
+ return_val_if_nok (error, FALSE);
klass->interfaces [i] = mono_class_from_mono_type (iface_type);
mono_metadata_free_type (iface_type);
- ensure_runtime_vtable (klass->interfaces [i], &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!ensure_runtime_vtable (klass->interfaces [i], error))
+ return FALSE;
}
klass->interfaces_inited = 1;
}
klass->fields = image_g_new0 (klass->image, MonoClassField, klass->field.count);
for (i = 0; i < klass->field.count; i++) {
- MonoError error;
klass->fields [i] = gklass->fields [i];
klass->fields [i].parent = klass;
- klass->fields [i].type = mono_class_inflate_generic_type_checked (gklass->fields [i].type, mono_class_get_context (klass), &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ klass->fields [i].type = mono_class_inflate_generic_type_checked (gklass->fields [i].type, mono_class_get_context (klass), error);
+ return_val_if_nok (error, FALSE);
}
}
/*We can only finish with this klass once it's parent has as well*/
if (gklass->wastypebuilder)
klass->wastypebuilder = TRUE;
- return;
+ return TRUE;
}
/**
if (!ensure_runtime_vtable (gklass, error))
return FALSE;
- fix_partial_generic_class (klass);
-
- return TRUE;
+ return fix_partial_generic_class (klass, error);
}
/**
klass->interfaces_inited = 1;
}
} else if (klass->generic_class){
- if (!ensure_generic_class_runtime_vtable (klass, error))
+ if (!ensure_generic_class_runtime_vtable (klass, error)) {
+ mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
return FALSE;
+ }
}
if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
}
static MonoMethod*
-mono_reflection_method_get_handle (MonoObject *method)
+mono_reflection_method_get_handle (MonoObject *method, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
MonoClass *klass = mono_object_class (method);
if (is_sr_mono_method (klass) || is_sr_mono_generic_method (klass)) {
MonoReflectionMethod *sr_method = (MonoReflectionMethod*)method;
MonoMethod *result;
/*FIXME move this to a proper method and unify with resolve_object*/
if (m->method_args) {
- result = mono_reflection_method_on_tb_inst_get_handle (m, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ result = mono_reflection_method_on_tb_inst_get_handle (m, error);
} else {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, error);
+ return_val_if_nok (error, NULL);
MonoClass *inflated_klass = mono_class_from_mono_type (type);
MonoMethod *mono_method;
}
void
-mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides)
+mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides, MonoError *error)
{
MonoReflectionTypeBuilder *tb;
int i, j, onum;
MonoReflectionMethod *m;
+ mono_error_init (error);
*overrides = NULL;
*num_overrides = 0;
for (j = 0; j < mono_array_length (mb->override_methods); ++j) {
m = mono_array_get (mb->override_methods, MonoReflectionMethod*, j);
- (*overrides) [onum * 2] = mono_reflection_method_get_handle ((MonoObject*)m);
+ (*overrides) [onum * 2] = mono_reflection_method_get_handle ((MonoObject*)m, error);
+ return_if_nok (error);
(*overrides) [onum * 2 + 1] = mb->mhandle;
g_assert (mb->mhandle);
}
klass->instance_size = MAX (klass->instance_size, real_size);
- mono_class_layout_fields (klass);
+ mono_class_layout_fields (klass, klass->instance_size);
}
static void
}
}
-MonoReflectionEvent *
-mono_reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
+static MonoReflectionEvent *
+reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
+
MonoEvent *event = g_new0 (MonoEvent, 1);
MonoClass *klass;
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
+ if (!is_ok (error)) {
+ g_free (event);
+ return NULL;
+ }
klass = mono_class_from_mono_type (type);
event->parent = klass;
}
#endif
- MonoReflectionEvent *ev_obj = mono_event_get_object_checked (mono_object_domain (tb), klass, event, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoReflectionEvent *ev_obj = mono_event_get_object_checked (mono_object_domain (tb), klass, event, error);
+ if (!is_ok (error)) {
+#ifndef MONO_SMALL_CONFIG
+ g_free (event->other);
+#endif
+ g_free (event);
+ return NULL;
+ }
return ev_obj;
}
+MonoReflectionEvent *
+mono_reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
+{
+ MonoError error;
+ MonoReflectionEvent *result = reflection_event_builder_get_event_info (tb, eb, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
static void
typebuilder_setup_events (MonoClass *klass, MonoError *error)
{
}
}
+struct remove_instantiations_user_data
+{
+ MonoClass *klass;
+ MonoError *error;
+};
+
static gboolean
remove_instantiations_of_and_ensure_contents (gpointer key,
gpointer value,
gpointer user_data)
{
+ struct remove_instantiations_user_data *data = (struct remove_instantiations_user_data*)user_data;
MonoType *type = (MonoType*)key;
- MonoClass *klass = (MonoClass*)user_data;
+ MonoClass *klass = data->klass;
+ gboolean already_failed = !is_ok (data->error);
+ MonoError lerror;
+ MonoError *error = already_failed ? &lerror : data->error;
if ((type->type == MONO_TYPE_GENERICINST) && (type->data.generic_class->container_class == klass)) {
- fix_partial_generic_class (mono_class_from_mono_type (type)); //Ensure it's safe to use it.
+ MonoClass *inst_klass = mono_class_from_mono_type (type);
+ //Ensure it's safe to use it.
+ if (!fix_partial_generic_class (inst_klass, error)) {
+ mono_class_set_failure (inst_klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ // Marked the class with failure, but since some other instantiation already failed,
+ // just report that one, and swallow the error from this one.
+ if (already_failed)
+ mono_error_cleanup (error);
+ }
return TRUE;
} else
return FALSE;
MonoReflectionType* res;
int i, j;
+ mono_error_init (&error);
+
domain = mono_object_domain (tb);
klass = mono_class_from_mono_type (tb->type.type);
* Check for user defined Type subclasses.
*/
RESOLVE_TYPE (tb->parent, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (tb->interfaces, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
if (tb->fields) {
for (i = 0; i < mono_array_length (tb->fields); ++i) {
MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)mono_array_get (tb->fields, gpointer, i);
if (fb) {
RESOLVE_TYPE (fb->type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (fb->modreq, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (fb->modopt, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
if (fb->marshal_info && fb->marshal_info->marshaltyperef) {
RESOLVE_TYPE (fb->marshal_info->marshaltyperef, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
}
}
MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)mono_array_get (tb->methods, gpointer, i);
if (mb) {
RESOLVE_TYPE (mb->rtype, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (mb->return_modreq, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (mb->return_modopt, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (mb->parameters, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
if (mb->param_modreq)
for (j = 0; j < mono_array_length (mb->param_modreq); ++j) {
check_array_for_usertypes (mono_array_get (mb->param_modreq, MonoArray*, j), &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
if (mb->param_modopt)
for (j = 0; j < mono_array_length (mb->param_modopt); ++j) {
check_array_for_usertypes (mono_array_get (mb->param_modopt, MonoArray*, j), &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
}
}
MonoReflectionCtorBuilder *mb = (MonoReflectionCtorBuilder *)mono_array_get (tb->ctors, gpointer, i);
if (mb) {
check_array_for_usertypes (mb->parameters, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
if (mb->param_modreq)
for (j = 0; j < mono_array_length (mb->param_modreq); ++j) {
check_array_for_usertypes (mono_array_get (mb->param_modreq, MonoArray*, j), &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
if (mb->param_modopt)
for (j = 0; j < mono_array_length (mb->param_modopt); ++j) {
check_array_for_usertypes (mono_array_get (mb->param_modopt, MonoArray*, j), &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
}
}
mono_loader_unlock ();
res = mono_type_get_object_checked (mono_object_domain (tb), &klass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_set_pending_exception (&error);
return res;
}
mono_domain_unlock (domain);
res = mono_type_get_object_checked (mono_object_domain (tb), &klass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_set_pending_exception (&error);
return res;
}
*
* Together with this we must ensure the contents of all instances to match the created type.
*/
- if (domain->type_hash && klass->generic_container)
- mono_g_hash_table_foreach_remove (domain->type_hash, remove_instantiations_of_and_ensure_contents, klass);
+ if (domain->type_hash && klass->generic_container) {
+ struct remove_instantiations_user_data data;
+ data.klass = klass;
+ data.error = &error;
+ mono_error_assert_ok (&error);
+ mono_g_hash_table_foreach_remove (domain->type_hash, remove_instantiations_of_and_ensure_contents, &data);
+ if (!is_ok (&error))
+ goto failure;
+ }
mono_domain_unlock (domain);
mono_loader_unlock ();
if (klass->enumtype && !mono_class_is_valid_enum (klass)) {
mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- mono_raise_exception (mono_get_exception_type_load (tb->name, NULL));
+ mono_error_set_type_load_class (&error, klass, "Not a valid enumeration");
+ goto failure_unlocked;
}
res = mono_type_get_object_checked (mono_object_domain (tb), &klass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
g_assert (res != (MonoReflectionType*)tb);
klass->wastypebuilder = TRUE;
mono_domain_unlock (domain);
mono_loader_unlock ();
- mono_error_raise_exception (&error);
+failure_unlocked:
+ mono_error_set_pending_exception (&error);
return NULL;
}
-void
-mono_reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam)
+static gboolean
+reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam, MonoError *error)
{
MonoGenericParamFull *param;
MonoImage *image;
MonoClass *pklass;
- MonoError error;
+
+ mono_error_init (error);
image = &gparam->tbuilder->module->dynamic_image->image;
param = mono_image_new0 (image, MonoGenericParamFull, 1);
- param->info.name = mono_string_to_utf8_image (image, gparam->name, &error);
- g_assert (mono_error_ok (&error));
+ param->info.name = mono_string_to_utf8_image (image, gparam->name, error);
+ mono_error_assert_ok (error);
param->param.num = gparam->index;
if (gparam->mbuilder) {
if (!gparam->mbuilder->generic_container) {
- MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->mbuilder->type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->mbuilder->type, error);
+ return_val_if_nok (error, FALSE);
MonoClass *klass = mono_class_from_mono_type (tb);
gparam->mbuilder->generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
param->param.owner = gparam->mbuilder->generic_container;
} else if (gparam->tbuilder) {
if (!gparam->tbuilder->generic_container) {
- MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->tbuilder, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->tbuilder, error);
+ return_val_if_nok (error, FALSE);
MonoClass *klass = mono_class_from_mono_type (tb);
gparam->tbuilder->generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
gparam->tbuilder->generic_container->owner.klass = klass;
mono_class_set_ref_info (pklass, gparam);
mono_image_append_class_to_reflection_info_set (pklass);
+
+ return TRUE;
+}
+
+void
+mono_reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam)
+{
+ MonoError error;
+ (void) reflection_initialize_generic_parameter (gparam, &error);
+ mono_error_set_pending_exception (&error);
}
+
MonoArray *
mono_reflection_sighelper_get_signature_local (MonoReflectionSigHelper *sig)
{
g_free (data);
}
-void
-mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
+static gboolean
+reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb, MonoError *error)
{
- MonoError error;
MonoReferenceQueue *queue;
MonoMethod *handle;
DynamicMethodReleaseData *release_data;
GSList *l;
int i;
- if (mono_runtime_is_shutting_down ())
- mono_raise_exception (mono_get_exception_invalid_operation (""));
+ mono_error_init (error);
+
+ if (mono_runtime_is_shutting_down ()) {
+ mono_error_set_generic_error (error, "System", "InvalidOperationException", "");
+ return FALSE;
+ }
if (!(queue = dynamic_method_queue)) {
mono_loader_lock ();
mono_loader_unlock ();
}
- sig = dynamic_method_to_signature (mb);
+ sig = dynamic_method_to_signature (mb, error);
+ return_val_if_nok (error, FALSE);
reflection_methodbuilder_from_dynamic_method (&rmb, mb);
handle_class = mono_defaults.methodhandle_class;
} else {
MonoException *ex = NULL;
- ref = resolve_object (mb->module->image, obj, &handle_class, NULL);
+ ref = resolve_object (mb->module->image, obj, &handle_class, NULL, error);
+ if (!is_ok (error)) {
+ g_free (rmb.refs);
+ return FALSE;
+ }
if (!ref)
ex = mono_get_exception_type_load (NULL, NULL);
else if (mono_security_core_clr_enabled ())
if (ex) {
g_free (rmb.refs);
- mono_raise_exception (ex);
- return;
+ mono_error_set_exception_instance (error, ex);
+ return FALSE;
}
}
}
if (mb->owner) {
- MonoType *owner_type = mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner, &error);
- if (!is_ok (&error)) {
+ MonoType *owner_type = mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner, error);
+ if (!is_ok (error)) {
g_free (rmb.refs);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return FALSE;
}
klass = mono_class_from_mono_type (owner_type);
} else {
domain->method_to_dyn_method = g_hash_table_new (NULL, NULL);
g_hash_table_insert (domain->method_to_dyn_method, handle, (gpointer)(size_t)mono_gchandle_new_weakref ((MonoObject *)mb, TRUE));
mono_domain_unlock (domain);
+
+ return TRUE;
+}
+
+void
+mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
+{
+ MonoError error;
+ (void) reflection_create_dynamic_method (mb, &error);
+ mono_error_set_pending_exception (&error);
}
#endif /* DISABLE_REFLECTION_EMIT */
* LOCKING: Take the loader lock
*/
gpointer
-mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
+mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
{
MonoDynamicImage *assembly = (MonoDynamicImage*)image;
MonoObject *obj;
MonoClass *klass;
+ mono_error_init (error);
+
obj = lookup_dyn_token (assembly, token);
if (!obj) {
if (valid_token)
g_error ("Could not find required dynamic token 0x%08x", token);
- else
+ else {
+ mono_error_set_execution_engine (error, "Could not find dynamic token 0x%08x", token);
return NULL;
+ }
}
if (!handle_class)
handle_class = &klass;
- return resolve_object (image, obj, handle_class, context);
+ gpointer result = resolve_object (image, obj, handle_class, context, error);
+ return result;
}
/*
* dynamic types.
*/
static void
-ensure_complete_type (MonoClass *klass)
+ensure_complete_type (MonoClass *klass, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
if (image_is_dynamic (klass->image) && !klass->wastypebuilder && mono_class_get_ref_info (klass)) {
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info (klass);
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_if_nok (error);
// Asserting here could break a lot of code
//g_assert (klass->wastypebuilder);
int i;
for (i = 0; i < inst->type_argc; ++i) {
- ensure_complete_type (mono_class_from_mono_type (inst->type_argv [i]));
+ ensure_complete_type (mono_class_from_mono_type (inst->type_argv [i]), error);
+ return_if_nok (error);
}
}
}
static gpointer
-resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context)
+resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
{
- MonoError error;
gpointer result = NULL;
+ mono_error_init (error);
+
if (strcmp (obj->vtable->klass->name, "String") == 0) {
- result = mono_string_intern_checked ((MonoString*)obj, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ result = mono_string_intern_checked ((MonoString*)obj, error);
+ return_val_if_nok (error, NULL);
*handle_class = mono_defaults.string_class;
g_assert (result);
} else if (strcmp (obj->vtable->klass->name, "MonoType") == 0) {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
+ return_val_if_nok (error, NULL);
MonoClass *mc = mono_class_from_mono_type (type);
- if (!mono_class_init (mc))
- mono_raise_exception (mono_class_get_exception_for_failure (mc));
+ if (!mono_class_init (mc)) {
+ mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (mc));
+ return NULL;
+ }
if (context) {
- MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, error);
+ return_val_if_nok (error, NULL);
result = mono_class_from_mono_type (inflated);
mono_metadata_free_type (inflated);
strcmp (obj->vtable->klass->name, "MonoGenericMethod") == 0) {
result = ((MonoReflectionMethod*)obj)->method;
if (context) {
- MonoError error;
- result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
+ mono_error_assert_ok (error);
}
*handle_class = mono_defaults.methodhandle_class;
g_assert (result);
/* Type is not yet created */
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)mb->type;
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_val_if_nok (error, NULL);
/*
* Hopefully this has been filled in by calling CreateType() on the
result = mb->mhandle;
}
if (context) {
- MonoError error;
- result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
+ mono_error_assert_ok (error);
}
*handle_class = mono_defaults.methodhandle_class;
} else if (strcmp (obj->vtable->klass->name, "ConstructorBuilder") == 0) {
if (!result) {
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)cb->type;
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_val_if_nok (error, NULL);
result = cb->mhandle;
}
if (context) {
- MonoError error;
- result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
+ mono_error_assert_ok (error);
}
*handle_class = mono_defaults.methodhandle_class;
} else if (strcmp (obj->vtable->klass->name, "MonoField") == 0) {
MonoClassField *field = ((MonoReflectionField*)obj)->field;
- ensure_complete_type (field->parent);
+ ensure_complete_type (field->parent, error);
+ return_val_if_nok (error, NULL);
+
if (context) {
- MonoType *inflated = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *inflated = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, error);
+ return_val_if_nok (error, NULL);
MonoClass *klass = mono_class_from_mono_type (inflated);
MonoClassField *inflated_field;
if (!result) {
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)fb->typeb;
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_val_if_nok (error, NULL);
result = fb->handle;
}
if (fb->handle && fb->handle->parent->generic_container) {
MonoClass *klass = fb->handle->parent;
- MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, context, error);
+ return_val_if_nok (error, NULL);
MonoClass *inflated = mono_class_from_mono_type (type);
*handle_class = mono_defaults.fieldhandle_class;
} else if (strcmp (obj->vtable->klass->name, "TypeBuilder") == 0) {
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)obj;
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
+ return_val_if_nok (error, NULL);
MonoClass *klass;
klass = type->data.klass;
result = klass;
}
else {
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_val_if_nok (error, NULL);
result = type->data.klass;
g_assert (result);
}
/* TODO: Copy type ? */
sig->ret = helper->return_type->type;
for (i = 0; i < nargs; ++i) {
- sig->params [i] = mono_type_array_get_and_resolve (helper->arguments, i, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ sig->params [i] = mono_type_array_get_and_resolve (helper->arguments, i, error);
+ if (!is_ok (error)) {
+ image_g_free (image, sig);
+ return NULL;
+ }
}
result = sig;
result = method->mhandle;
*handle_class = mono_defaults.methodhandle_class;
} else if (strcmp (obj->vtable->klass->name, "GenericTypeParameterBuilder") == 0) {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- type = mono_class_inflate_generic_type_checked (type, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
+ return_val_if_nok (error, NULL);
+ type = mono_class_inflate_generic_type_checked (type, context, error);
+ return_val_if_nok (error, NULL);
result = mono_class_from_mono_type (type);
*handle_class = mono_defaults.typehandle_class;
g_assert (result);
mono_metadata_free_type (type);
} else if (strcmp (obj->vtable->klass->name, "MonoGenericClass") == 0) {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- type = mono_class_inflate_generic_type_checked (type, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
+ return_val_if_nok (error, NULL);
+ type = mono_class_inflate_generic_type_checked (type, context, error);
+ return_val_if_nok (error, NULL);
result = mono_class_from_mono_type (type);
*handle_class = mono_defaults.typehandle_class;
else
g_error ("resolve_object:: can't handle a FTBI with base_method of type %s", mono_type_get_full_name (mono_object_class (f->fb)));
- MonoType *finst = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- type = mono_class_inflate_generic_type_checked (finst, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *finst = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst, error);
+ return_val_if_nok (error, NULL);
+ type = mono_class_inflate_generic_type_checked (finst, context, error);
+ return_val_if_nok (error, NULL);
inflated = mono_class_from_mono_type (type);
result = field = mono_class_get_field_from_name (inflated, mono_field_get_name (field));
- ensure_complete_type (field->parent);
+ ensure_complete_type (field->parent, error);
+ if (!is_ok (error)) {
+ mono_metadata_free_type (type);
+ return NULL;
+ }
+
g_assert (result);
mono_metadata_free_type (type);
*handle_class = mono_defaults.fieldhandle_class;
} else if (strcmp (obj->vtable->klass->name, "ConstructorOnTypeBuilderInst") == 0) {
MonoReflectionCtorOnTypeBuilderInst *c = (MonoReflectionCtorOnTypeBuilderInst*)obj;
- MonoType *cinst = mono_reflection_type_get_handle ((MonoReflectionType*)c->inst, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- MonoType *type = mono_class_inflate_generic_type_checked (cinst, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *cinst = mono_reflection_type_get_handle ((MonoReflectionType*)c->inst, error);
+ return_val_if_nok (error, NULL);
+ MonoType *type = mono_class_inflate_generic_type_checked (cinst, context, error);
+ return_val_if_nok (error, NULL);
MonoClass *inflated_klass = mono_class_from_mono_type (type);
MonoMethod *method;
} else if (strcmp (obj->vtable->klass->name, "MethodOnTypeBuilderInst") == 0) {
MonoReflectionMethodOnTypeBuilderInst *m = (MonoReflectionMethodOnTypeBuilderInst*)obj;
if (m->method_args) {
- result = mono_reflection_method_on_tb_inst_get_handle (m, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ result = mono_reflection_method_on_tb_inst_get_handle (m, error);
+ return_val_if_nok (error, NULL);
if (context) {
- result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, &error);
- mono_error_assert_ok (&error);
+ result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
+ mono_error_assert_ok (error);
}
} else {
- MonoType *minst = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- MonoType *type = mono_class_inflate_generic_type_checked (minst, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *minst = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, error);
+ return_val_if_nok (error, NULL);
+ MonoType *type = mono_class_inflate_generic_type_checked (minst, context, error);
+ return_val_if_nok (error, NULL);
MonoClass *inflated_klass = mono_class_from_mono_type (type);
MonoMethod *method;
gpointer iter;
char *name;
- mtype = mono_reflection_type_get_handle (m->parent, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mtype = mono_reflection_type_get_handle (m->parent, error);
+ return_val_if_nok (error, NULL);
klass = mono_class_from_mono_type (mtype);
/* Find the method */
is_sre_byref (mono_object_get_class(obj)) ||
is_sre_pointer (mono_object_get_class(obj))) {
MonoReflectionType *ref_type = (MonoReflectionType *)obj;
- MonoType *type = mono_reflection_type_get_handle (ref_type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle (ref_type, error);
+ return_val_if_nok (error, NULL);
if (context) {
- MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, error);
+ return_val_if_nok (error, NULL);
result = mono_class_from_mono_type (inflated);
mono_metadata_free_type (inflated);
}
void
-mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides)
+mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides, MonoError *error)
{
+ mono_error_init (error);
*overrides = NULL;
*num_overrides = 0;
}
}
gboolean
-mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass)
+mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass, MonoError *error)
{
- MonoError error;
MonoObject *res, *exc;
void *params [1];
static MonoMethod *method = NULL;
+ mono_error_init (error);
+
if (method == NULL) {
method = mono_class_get_method_from_name (mono_class_get_type_builder_class (), "IsAssignableTo", 1);
g_assert (method);
g_assert (mono_class_get_ref_info (klass));
g_assert (!strcmp (((MonoObject*)(mono_class_get_ref_info (klass)))->vtable->klass->name, "TypeBuilder"));
- params [0] = mono_type_get_object_checked (mono_domain_get (), &oklass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ params [0] = mono_type_get_object_checked (mono_domain_get (), &oklass->byval_arg, error);
+ return_val_if_nok (error, FALSE);
- res = mono_runtime_try_invoke (method, (MonoObject*)(mono_class_get_ref_info (klass)), params, &exc, &error);
+ res = mono_runtime_try_invoke (method, (MonoObject*)(mono_class_get_ref_info (klass)), params, &exc, error);
- if (exc || !mono_error_ok (&error)) {
- mono_error_cleanup (&error);
+ if (exc || !mono_error_ok (error)) {
+ mono_error_cleanup (error);
return FALSE;
} else
return *(MonoBoolean*)mono_object_unbox (res);
MONO_API MonoArray* mono_reflection_get_custom_attrs (MonoObject *obj);
MONO_RT_EXTERNAL_ONLY
MONO_API MonoArray* mono_reflection_get_custom_attrs_data (MonoObject *obj);
+MONO_RT_EXTERNAL_ONLY
MONO_API MonoArray* mono_reflection_get_custom_attrs_blob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *porpValues, MonoArray *fields, MonoArray* fieldValues);
MONO_RT_EXTERNAL_ONLY
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011-2014 Xamarin, Inc (http://www.xamarin.com)
*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
mparams[i] = *((gpointer *)params [i]);
} else {
/* runtime_invoke expects a boxed instance */
- if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i])))
- mparams[i] = mono_nullable_box ((guint8 *)params [i], klass);
- else
+ if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
+ mparams[i] = mono_nullable_box ((guint8 *)params [i], klass, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ } else
mparams[i] = params [i];
}
} else {
case MONO_TYPE_U8:
case MONO_TYPE_R4:
case MONO_TYPE_R8: {
- return mono_value_box (domain, mono_object_class (val), ((char*)val) + sizeof(MonoObject));
+ MonoObject *res = mono_value_box_checked (domain, mono_object_class (val), ((char*)val) + sizeof(MonoObject), &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return res;
+
}
case MONO_TYPE_STRING: {
MonoString *str = (MonoString *) val;
* Jonathan Pryor
*
* Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Sebastien Pouliot <sebastien@ximian.com>
*
* Copyright 2007-2010 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <mono/metadata/class-internals.h>
* Transparent code cannot access to Critical fields and can only use
* them if they are visible from it's point of view.
*
- * A FieldAccessException is thrown if the field is cannot be accessed.
+ * Returns TRUE if acess is allowed. Otherwise returns FALSE and sets @error to a FieldAccessException if the field is cannot be accessed.
*/
-void
-mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field)
+gboolean
+mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field, MonoError *error)
{
+ mono_error_init (error);
MonoMethod *caller = get_reflection_caller ();
/* CoreCLR restrictions applies to Transparent code/caller */
if (mono_security_core_clr_method_level (caller, TRUE) != MONO_SECURITY_CORE_CLR_TRANSPARENT)
- return;
+ return TRUE;
if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION) {
if (!mono_security_core_clr_is_platform_image (mono_field_get_parent(field)->image))
- return;
+ return TRUE;
}
/* Transparent code cannot [get|set]value on Critical fields */
if (mono_security_core_clr_class_level (mono_field_get_parent (field)) == MONO_SECURITY_CORE_CLR_CRITICAL) {
- mono_raise_exception (get_field_access_exception (
+ mono_error_set_exception_instance (error, get_field_access_exception (
"Transparent method %s cannot get or set Critical field %s.",
caller, field));
+ return FALSE;
}
/* also it cannot access a fields that is not visible from it's (caller) point of view */
if (!check_field_access (caller, field)) {
- mono_raise_exception (get_field_access_exception (
+ mono_error_set_exception_instance (error, get_field_access_exception (
"Transparent method %s cannot get or set private/internal field %s.",
caller, field));
+ return FALSE;
}
+ return TRUE;
}
/*
* Transparent code cannot call Critical methods and can only call them
* if they are visible from it's point of view.
*
- * A MethodAccessException is thrown if the field is cannot be accessed.
+ * If access is allowed returns TRUE. Returns FALSE and sets @error to a MethodAccessException if the field is cannot be accessed.
*/
-void
-mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method)
+gboolean
+mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method, MonoError *error)
{
+ mono_error_init (error);
MonoMethod *caller = get_reflection_caller ();
/* CoreCLR restrictions applies to Transparent code/caller */
if (mono_security_core_clr_method_level (caller, TRUE) != MONO_SECURITY_CORE_CLR_TRANSPARENT)
- return;
+ return TRUE;
if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION) {
if (!mono_security_core_clr_is_platform_image (method->klass->image))
- return;
+ return TRUE;
}
/* Transparent code cannot invoke, even using reflection, Critical code */
if (mono_security_core_clr_method_level (method, TRUE) == MONO_SECURITY_CORE_CLR_CRITICAL) {
- mono_raise_exception (get_method_access_exception (
+ mono_error_set_exception_instance (error, get_method_access_exception (
"Transparent method %s cannot invoke Critical method %s.",
caller, method));
+ return FALSE;
}
/* also it cannot invoke a method that is not visible from it's (caller) point of view */
if (!check_method_access (caller, method)) {
- mono_raise_exception (get_method_access_exception (
+ mono_error_set_exception_instance (error, get_method_access_exception (
"Transparent method %s cannot invoke private/internal method %s.",
caller, method));
+ return FALSE;
}
+ return TRUE;
}
/*
/*
* mono_security_core_clr_ensure_delegate_creation:
*
- * Return TRUE if a delegate can be created on the specified method.
- * CoreCLR also affect the binding, so throwOnBindFailure must be
- * FALSE to let this function return (FALSE) normally, otherwise (if
- * throwOnBindFailure is TRUE) it will throw an ArgumentException.
+ * Return TRUE if a delegate can be created on the specified
+ * method. CoreCLR can also affect the binding, this function may
+ * return (FALSE) and set @error to an ArgumentException.
*
- * A MethodAccessException is thrown if the specified method is not
+ * @error is set to a MethodAccessException if the specified method is not
* visible from the caller point of view.
*/
gboolean
-mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, gboolean throwOnBindFailure)
+mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, MonoError *error)
{
MonoMethod *caller;
+ mono_error_init (error);
+
/* note: mscorlib creates delegates to avoid reflection (optimization), we ignore those cases */
if (can_avoid_corlib_reflection_delegate_optimization (method))
return TRUE;
/* otherwise it (as a Transparent caller) cannot create a delegate on a Critical method... */
if (mono_security_core_clr_method_level (method, TRUE) == MONO_SECURITY_CORE_CLR_CRITICAL) {
- /* but this throws only if 'throwOnBindFailure' is TRUE */
- if (!throwOnBindFailure)
- return FALSE;
-
- mono_raise_exception (get_argument_exception (
+ mono_error_set_exception_instance (error, get_argument_exception (
"Transparent method %s cannot create a delegate on Critical method %s.",
caller, method));
+ return FALSE;
}
if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_DELEGATE) {
/* also it cannot create the delegate on a method that is not visible from it's (caller) point of view */
if (!check_method_access (caller, method)) {
- mono_raise_exception (get_method_access_exception (
+ mono_error_set_exception_instance (error, get_method_access_exception (
"Transparent method %s cannot create a delegate on private/internal method %s.",
caller, method));
+ return FALSE;
}
return TRUE;
return FALSE;
}
-void
-mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field)
+gboolean
+mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field, MonoError *error)
{
+ mono_error_init (error);
+ return TRUE;
}
void
-mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method)
+mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method, MonoError *error)
{
+ mono_error_init (error);
+ return TRUE;
}
gboolean
-mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, gboolean throwOnBindFailure)
+mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, MonoError *error)
{
+ mono_error_init (error);
return TRUE;
}
extern void mono_security_core_clr_check_inheritance (MonoClass *klass);
extern void mono_security_core_clr_check_override (MonoClass *klass, MonoMethod *override, MonoMethod *base);
-extern void mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field);
-extern void mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method);
-extern gboolean mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, gboolean throwOnBindFailure);
+extern gboolean
+mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field, MonoError *error);
+extern gboolean
+mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method, MonoError *error);
+extern gboolean mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, MonoError *error);
extern MonoException* mono_security_core_clr_ensure_dynamic_method_resolved_object (gpointer ref, MonoClass *handle_class);
extern gboolean mono_security_core_clr_can_access_internals (MonoImage *accessing, MonoImage* accessed);
* Sebastien Pouliot <sebastien@ximian.com>
*
* Copyright 2005-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "security-manager.h"
* Sebastien Pouliot <sebastien@ximian.com>
*
* Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _MONO_METADATA_SECURITY_MANAGER_H_
/*
* Copyright 2015 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SEQ_POINTS_DATA_H__
*
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGENBRIDGEINTERNAL_H__
*
* Copyright 2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
- *
* Copyright 2001-2003 Ximian, Inc
* Copyright 2003-2010 Novell, Inc.
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
bridge_callbacks = *callbacks;
if (!bridge_processor.reset_data)
- sgen_old_bridge_init (&bridge_processor);
+ sgen_new_bridge_init (&bridge_processor);
}
static gboolean
/*
* Copyright 2011 Novell, Inc.
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifdef SGEN_DEFINE_OBJECT_VTABLE
#define SGEN_TV_DECLARE(name) gint64 name
#define SGEN_TV_GETTIME(tv) tv = mono_100ns_ticks ()
-#define SGEN_TV_ELAPSED(start,end) ((long)(end-start))
+#define SGEN_TV_ELAPSED(start,end) ((gint64)(end-start))
typedef MonoSemType SgenSemaphore;
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#include "metadata/handle.h"
#include "utils/mono-memory-model.h"
#include "utils/mono-logger-internals.h"
+#include "sgen/sgen-thread-pool.h"
#ifdef HEAVY_STATISTICS
static guint64 stat_wbarrier_set_arrayref = 0;
#define ARRAY_OBJ_INDEX(ptr,array,elem_size) (((char*)(ptr) - ((char*)(array) + G_STRUCT_OFFSET (MonoArray, vector))) / (elem_size))
gboolean
-sgen_client_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, gboolean mod_union, ScanCopyContext ctx)
+sgen_client_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, ScanCopyContext ctx)
{
MonoVTable *vt = SGEN_LOAD_VTABLE (obj);
MonoClass *klass = vt->klass;
for (; elem < card_end; elem += elem_size)
scan_vtype_func (obj, elem, desc, ctx.queue BINARY_PROTOCOL_ARG (elem_size));
} else {
- CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
+ ScanPtrFieldFunc scan_ptr_field_func = ctx.ops->scan_ptr_field;
HEAVY_STAT (++los_array_cards);
- for (; elem < card_end; elem += SIZEOF_VOID_P) {
- GCObject *new_;
- gpointer old = *(gpointer*)elem;
- if ((mod_union && old) || G_UNLIKELY (sgen_ptr_in_nursery (old))) {
- HEAVY_STAT (++los_array_remsets);
- copy_func ((GCObject**)elem, ctx.queue);
- new_ = *(GCObject **)elem;
- if (G_UNLIKELY (sgen_ptr_in_nursery (new_)))
- sgen_add_to_global_remset (elem, new_);
- }
- }
+ for (; elem < card_end; elem += SIZEOF_VOID_P)
+ scan_ptr_field_func (obj, (GCObject**)elem, ctx.queue);
}
binary_protocol_card_scan (first_elem, elem - first_elem);
void
mono_gc_base_cleanup (void)
{
+ sgen_thread_pool_shutdown ();
}
gboolean
*
* Copyright 2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
- *
* Copyright 2001-2003 Ximian, Inc
* Copyright 2003-2010 Novell, Inc.
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
DEF_QSORT_INLINE(hash_entries, HashEntry*, compare_hash_entries)
-static unsigned long step_1, step_2, step_3, step_4, step_5, step_6;
+static gint64 step_1, step_2, step_3, step_4, step_5, step_6;
static int fist_pass_links, second_pass_links, sccs_links;
static int max_sccs_links = 0;
*
* Copyright 2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
- *
* Copyright 2001-2003 Ximian, Inc
* Copyright 2003-2010 Novell, Inc.
- *
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
DEF_QSORT_INLINE(hash_entries, HashEntry*, compare_hash_entries)
-static unsigned long step_1, step_2, step_3, step_4, step_5, step_6;
+static gint64 step_1, step_2, step_3, step_4, step_5, step_6;
static int fist_pass_links, second_pass_links, sccs_links;
static int max_sccs_links = 0;
* João Matos (joao.matos@xamarin.com)
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
}
#endif
-#endif
\ No newline at end of file
+#endif
* Copyright 2010 Novell, Inc (http://www.novell.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2010 Novell, Inc (http://www.novell.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2011 Xamarin, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2011 Novell, Inc (http://www.novell.com)
* Copyright 2014 Xamarin Inc (http://www.xamarin.com)
*
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
*
* Copyright 2001-2003 Ximian, Inc
* Copyright 2003-2010 Novell, Inc.
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2011 Xamarin, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Author:
* Rodrigo Kumpera (kumpera@gmail.com)
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _MONO_SGEN_TOGGLEREF_H_
*
* This file has been re-licensed under the MIT License:
* http://opensource.org/licenses/MIT
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
static MonoObject*
int_to_object (MonoDomain *domain, int val)
{
- return mono_value_box (domain, mono_get_int32_class (), &val);
+ MonoError error;
+ MonoObject *result = mono_value_box_checked (domain, mono_get_int32_class (), &val, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return result;
}
void
*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <stdlib.h>
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2015 Xamarin, Inc (https://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
//
*
* (C) Ximian, Inc. 2002
* Copyright 2015 Xamarin, Inc (https://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __METADATA_SYSMATH_H__
* Ludovic Henry (ludovic.henry@xamarin.com)
*
* Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
static void
wait_callback (gint fd, gint events, gpointer user_data)
{
+ MonoError error;
+
if (mono_runtime_is_shutting_down ())
return;
if (list && (events & EVENT_IN) != 0) {
MonoIOSelectorJob *job = get_job_for_event (&list, EVENT_IN);
- if (job)
- mono_threadpool_ms_enqueue_work_item (((MonoObject*) job)->vtable->domain, (MonoObject*) job);
+ if (job) {
+ mono_threadpool_ms_enqueue_work_item (((MonoObject*) job)->vtable->domain, (MonoObject*) job, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ }
+
}
if (list && (events & EVENT_OUT) != 0) {
MonoIOSelectorJob *job = get_job_for_event (&list, EVENT_OUT);
- if (job)
- mono_threadpool_ms_enqueue_work_item (((MonoObject*) job)->vtable->domain, (MonoObject*) job);
+ if (job) {
+ mono_threadpool_ms_enqueue_work_item (((MonoObject*) job)->vtable->domain, (MonoObject*) job, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ }
}
remove_fd = (events & EVENT_ERR) == EVENT_ERR;
static void
selector_thread (gpointer data)
{
+ MonoError error;
MonoGHashTable *states;
io_selector_running = TRUE;
memset (update, 0, sizeof (ThreadPoolIOUpdate));
}
- for (; list; list = mono_mlist_remove_item (list, list))
- mono_threadpool_ms_enqueue_work_item (mono_object_domain (mono_mlist_get_data (list)), mono_mlist_get_data (list));
+ for (; list; list = mono_mlist_remove_item (list, list)) {
+ mono_threadpool_ms_enqueue_work_item (mono_object_domain (mono_mlist_get_data (list)), mono_mlist_get_data (list), &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ }
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: del fd %3d", fd);
threadpool_io->backend.remove_fd (fd);
* Ludovic Henry (ludovic.henry@xamarin.com)
*
* Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
//
mono_coop_mutex_unlock (&threadpool->active_threads_lock);
}
-void
-mono_threadpool_ms_enqueue_work_item (MonoDomain *domain, MonoObject *work_item)
+gboolean
+mono_threadpool_ms_enqueue_work_item (MonoDomain *domain, MonoObject *work_item, MonoError *error)
{
static MonoClass *threadpool_class = NULL;
static MonoMethod *unsafe_queue_custom_work_item_method = NULL;
- MonoError error;
MonoDomain *current_domain;
MonoBoolean f;
gpointer args [2];
+ mono_error_init (error);
g_assert (work_item);
if (!threadpool_class)
current_domain = mono_domain_get ();
if (current_domain == domain) {
- mono_runtime_invoke_checked (unsafe_queue_custom_work_item_method, NULL, args, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_runtime_invoke_checked (unsafe_queue_custom_work_item_method, NULL, args, error);
+ return_val_if_nok (error, FALSE);
} else {
mono_thread_push_appdomain_ref (domain);
if (mono_domain_set (domain, FALSE)) {
- mono_runtime_invoke_checked (unsafe_queue_custom_work_item_method, NULL, args, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_runtime_invoke_checked (unsafe_queue_custom_work_item_method, NULL, args, error);
+ if (!is_ok (error)) {
+ mono_thread_pop_appdomain_ref ();
+ return FALSE;
+ }
mono_domain_set (current_domain, TRUE);
}
mono_thread_pop_appdomain_ref ();
}
+ return TRUE;
}
/* LOCKING: threadpool->domains_lock must be held */
if (interrupted)
goto done;
- if (mono_coop_cond_timedwait (&threadpool->parked_threads_cond, &threadpool->active_threads_lock, rand_next ((void **)rand_handle, 5 * 1000, 60 * 1000)) != 0)
+ if (mono_coop_cond_timedwait (&threadpool->parked_threads_cond, &threadpool->active_threads_lock, rand_next (&rand_handle, 5 * 1000, 60 * 1000)) != 0)
timeout = TRUE;
mono_thread_info_uninstall_interrupt (&interrupted);
}
MonoAsyncResult *
-mono_threadpool_ms_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMethod *method, gpointer *params)
+mono_threadpool_ms_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMethod *method, gpointer *params, MonoError *error)
{
static MonoClass *async_call_klass = NULL;
- MonoError error;
MonoMethodMessage *message;
MonoAsyncResult *async_result;
MonoAsyncCall *async_call;
mono_lazy_initialize (&status, initialize);
+ mono_error_init (error);
+
message = mono_method_call_message_new (method, params, mono_get_delegate_invoke (method->klass), (params != NULL) ? (&async_callback) : NULL, (params != NULL) ? (&state) : NULL);
- async_call = (MonoAsyncCall*) mono_object_new_checked (domain, async_call_klass, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ async_call = (MonoAsyncCall*) mono_object_new_checked (domain, async_call_klass, error);
+ return_val_if_nok (error, NULL);
MONO_OBJECT_SETREF (async_call, msg, message);
MONO_OBJECT_SETREF (async_call, state, state);
async_result = mono_async_result_new (domain, NULL, async_call->state, NULL, (MonoObject*) async_call);
MONO_OBJECT_SETREF (async_result, async_delegate, target);
- mono_threadpool_ms_enqueue_work_item (domain, (MonoObject*) async_result);
+ mono_threadpool_ms_enqueue_work_item (domain, (MonoObject*) async_result, error);
+ return_val_if_nok (error, NULL);
return async_result;
}
ves_icall_System_Threading_ThreadPool_ReportThreadStatus (MonoBoolean is_working)
{
// TODO
- mono_raise_exception (mono_get_exception_not_implemented (NULL));
+ MonoError error;
+ mono_error_set_not_implemented (&error, "");
+ mono_error_set_pending_exception (&error);
}
MonoBoolean
ves_icall_System_Threading_ThreadPool_PostQueuedCompletionStatus (MonoNativeOverlapped *native_overlapped)
{
/* This copy the behavior of the current Mono implementation */
- mono_raise_exception (mono_get_exception_not_implemented (NULL));
+ MonoError error;
+ mono_error_set_not_implemented (&error, "");
+ mono_error_set_pending_exception (&error);
return FALSE;
}
mono_threadpool_ms_cleanup (void);
MonoAsyncResult *
-mono_threadpool_ms_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMethod *method, gpointer *params);
+mono_threadpool_ms_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMethod *method, gpointer *params, MonoError *error);
MonoObject *
mono_threadpool_ms_end_invoke (MonoAsyncResult *ares, MonoArray **out_args, MonoObject **exc);
/* Internals */
-void
-mono_threadpool_ms_enqueue_work_item (MonoDomain *domain, MonoObject *work_item);
+gboolean
+mono_threadpool_ms_enqueue_work_item (MonoDomain *domain, MonoObject *work_item, MonoError *error);
#endif // _MONO_THREADPOOL_MICROSOFT_H_
*
* (C) 2001 Ximian, Inc
* (C) Copyright 2002-2006 Novell, Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _MONO_METADATA_THREADS_TYPES_H_
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Rodrigo Kumpera
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
if (!ctx.valid)
goto cleanup;
- original_bb = bb = mono_basic_block_split (method, &error);
+ original_bb = bb = mono_basic_block_split (method, &error, ctx.header);
if (!mono_error_ok (&error)) {
ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (&error)));
mono_error_cleanup (&error);
mini-x86.c \
mini-x86.h \
exceptions-x86.c \
- tramp-x86.c
+ tramp-x86.c \
+ mini-x86-gsharedvt.c \
+ tramp-x86-gsharedvt.c
amd64_sources = \
mini-amd64.c \
mini-amd64.h \
exceptions-amd64.c \
- tramp-amd64.c
+ tramp-amd64.c \
+ mini-amd64-gsharedvt.c \
+ mini-amd64-gsharedvt.h \
+ tramp-amd64-gsharedvt.c
ppc_sources = \
mini-ppc.c \
mini-arm.h \
mini-arm-tls.h \
exceptions-arm.c \
- tramp-arm.c
+ tramp-arm.c \
+ mini-arm-gsharedvt.c \
+ tramp-arm-gsharedvt.c
arm64_sources = \
mini-arm64.c \
mini-arm64.h \
exceptions-arm64.c \
- tramp-arm64.c
+ tramp-arm64.c \
+ mini-arm64-gsharedvt.c \
+ tramp-arm64-gsharedvt.c
mips_sources = \
mini-mips.c \
graph.c \
mini-codegen.c \
mini-exceptions.c \
+ mini-exceptions-native-unwinder.c \
mini-trampolines.c \
branch-opts.c \
mini-generic-sharing.c \
* (C) 2002 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#ifdef TARGET_ARM64
-#include "../../../mono-extensions/mono/mini/aot-compiler-arm64.c"
+
+/* Load the contents of GOT_SLOT into dreg, clobbering ip0 */
+static void
+arm64_emit_load_got_slot (MonoAotCompile *acfg, int dreg, int got_slot)
+{
+ int offset;
+
+ g_assert (acfg->fp);
+ emit_unset_mode (acfg);
+ /* r16==ip0 */
+ offset = (int)(got_slot * sizeof (gpointer));
+#ifdef TARGET_MACH
+ /* clang's integrated assembler */
+ fprintf (acfg->fp, "adrp x16, %s@PAGE+%d\n", acfg->got_symbol, offset & 0xfffff000);
+ fprintf (acfg->fp, "add x16, x16, %s@PAGEOFF\n", acfg->got_symbol);
+ fprintf (acfg->fp, "ldr x%d, [x16, #%d]\n", dreg, offset & 0xfff);
+#else
+ /* Linux GAS */
+ fprintf (acfg->fp, "adrp x16, %s+%d\n", acfg->got_symbol, offset & 0xfffff000);
+ fprintf (acfg->fp, "add x16, x16, :lo12:%s\n", acfg->got_symbol);
+ fprintf (acfg->fp, "ldr x%d, [x16, %d]\n", dreg, offset & 0xfff);
+#endif
+}
+
+static void
+arm64_emit_objc_selector_ref (MonoAotCompile *acfg, guint8 *code, int index, int *code_size)
+{
+ int reg;
+
+ g_assert (acfg->fp);
+ emit_unset_mode (acfg);
+
+ /* ldr rt, target */
+ reg = arm_get_ldr_lit_reg (code);
+
+ fprintf (acfg->fp, "adrp x%d, L_OBJC_SELECTOR_REFERENCES_%d@PAGE\n", reg, index);
+ fprintf (acfg->fp, "add x%d, x%d, L_OBJC_SELECTOR_REFERENCES_%d@PAGEOFF\n", reg, reg, index);
+ fprintf (acfg->fp, "ldr x%d, [x%d]\n", reg, reg);
+
+ *code_size = 12;
+}
+
+static void
+arm64_emit_direct_call (MonoAotCompile *acfg, const char *target, gboolean external, gboolean thumb, MonoJumpInfo *ji, int *call_size)
+{
+ g_assert (acfg->fp);
+ emit_unset_mode (acfg);
+ if (ji && ji->relocation == MONO_R_ARM64_B) {
+ fprintf (acfg->fp, "b %s\n", target);
+ } else {
+ if (ji)
+ g_assert (ji->relocation == MONO_R_ARM64_BL);
+ fprintf (acfg->fp, "bl %s\n", target);
+ }
+ *call_size = 4;
+}
+
+static void
+arm64_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *code_size)
+{
+ int reg;
+
+ /* ldr rt, target */
+ reg = arm_get_ldr_lit_reg (code);
+ arm64_emit_load_got_slot (acfg, reg, got_slot);
+ *code_size = 12;
+}
+
+static void
+arm64_emit_plt_entry (MonoAotCompile *acfg, const char *got_symbol, int offset, int info_offset)
+{
+ arm64_emit_load_got_slot (acfg, ARMREG_R16, offset / sizeof (gpointer));
+ fprintf (acfg->fp, "br x16\n");
+ /* Used by mono_aot_get_plt_info_offset () */
+ fprintf (acfg->fp, "%s %d\n", acfg->inst_directive, info_offset);
+}
+
+static void
+arm64_emit_tramp_page_common_code (MonoAotCompile *acfg, int pagesize, int arg_reg, int *size)
+{
+ guint8 buf [256];
+ guint8 *code;
+ int imm;
+
+ /* The common code */
+ code = buf;
+ imm = pagesize;
+ /* The trampoline address is in IP0 */
+ arm_movzx (code, ARMREG_IP1, imm & 0xffff, 0);
+ arm_movkx (code, ARMREG_IP1, (imm >> 16) & 0xffff, 16);
+ /* Compute the data slot address */
+ arm_subx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
+ /* Trampoline argument */
+ arm_ldrx (code, arg_reg, ARMREG_IP0, 0);
+ /* Address */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 8);
+ arm_brx (code, ARMREG_IP0);
+
+ /* Emit it */
+ emit_code_bytes (acfg, buf, code - buf);
+
+ *size = code - buf;
+}
+
+static void
+arm64_emit_tramp_page_specific_code (MonoAotCompile *acfg, int pagesize, int common_tramp_size, int specific_tramp_size)
+{
+ guint8 buf [256];
+ guint8 *code;
+ int i, count;
+
+ count = (pagesize - common_tramp_size) / specific_tramp_size;
+ for (i = 0; i < count; ++i) {
+ code = buf;
+ arm_adrx (code, ARMREG_IP0, code);
+ /* Branch to the generic code */
+ arm_b (code, code - 4 - (i * specific_tramp_size) - common_tramp_size);
+ /* This has to be 2 pointers long */
+ arm_nop (code);
+ arm_nop (code);
+ g_assert (code - buf == specific_tramp_size);
+ emit_code_bytes (acfg, buf, code - buf);
+ }
+}
+
+static void
+arm64_emit_specific_trampoline_pages (MonoAotCompile *acfg)
+{
+ guint8 buf [128];
+ guint8 *code;
+ guint8 *labels [16];
+ int common_tramp_size;
+ int specific_tramp_size = 2 * 8;
+ int imm, pagesize;
+ char symbol [128];
+
+ if (!acfg->aot_opts.use_trampolines_page)
+ return;
+
+#ifdef TARGET_MACH
+ /* Have to match the target pagesize */
+ pagesize = 16384;
+#else
+ pagesize = mono_pagesize ();
+#endif
+ acfg->tramp_page_size = pagesize;
+
+ /* The specific trampolines */
+ sprintf (symbol, "%sspecific_trampolines_page", acfg->user_symbol_prefix);
+ emit_alignment (acfg, pagesize);
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
+
+ /* The common code */
+ arm64_emit_tramp_page_common_code (acfg, pagesize, ARMREG_IP1, &common_tramp_size);
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_SPECIFIC] = common_tramp_size;
+
+ arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
+
+ /* The rgctx trampolines */
+ /* These are the same as the specific trampolines, but they load the argument into MONO_ARCH_RGCTX_REG */
+ sprintf (symbol, "%srgctx_trampolines_page", acfg->user_symbol_prefix);
+ emit_alignment (acfg, pagesize);
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
+
+ /* The common code */
+ arm64_emit_tramp_page_common_code (acfg, pagesize, MONO_ARCH_RGCTX_REG, &common_tramp_size);
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = common_tramp_size;
+
+ arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
+
+ /* The gsharedvt arg trampolines */
+ /* These are the same as the specific trampolines */
+ sprintf (symbol, "%sgsharedvt_arg_trampolines_page", acfg->user_symbol_prefix);
+ emit_alignment (acfg, pagesize);
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
+
+ arm64_emit_tramp_page_common_code (acfg, pagesize, ARMREG_IP1, &common_tramp_size);
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = common_tramp_size;
+
+ arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
+
+ /* The IMT trampolines */
+ sprintf (symbol, "%simt_trampolines_page", acfg->user_symbol_prefix);
+ emit_alignment (acfg, pagesize);
+ emit_global (acfg, symbol, TRUE);
+ emit_label (acfg, symbol);
+
+ code = buf;
+ imm = pagesize;
+ /* The trampoline address is in IP0 */
+ arm_movzx (code, ARMREG_IP1, imm & 0xffff, 0);
+ arm_movkx (code, ARMREG_IP1, (imm >> 16) & 0xffff, 16);
+ /* Compute the data slot address */
+ arm_subx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
+ /* Trampoline argument */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_IP0, 0);
+
+ /* Same as arch_emit_imt_thunk () */
+ labels [0] = code;
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 0);
+ arm_cmpx (code, ARMREG_IP0, MONO_ARCH_RGCTX_REG);
+ labels [1] = code;
+ arm_bcc (code, ARMCOND_EQ, 0);
+
+ /* End-of-loop check */
+ labels [2] = code;
+ arm_cbzx (code, ARMREG_IP0, 0);
+
+ /* Loop footer */
+ arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 2 * 8);
+ arm_b (code, labels [0]);
+
+ /* Match */
+ mono_arm_patch (labels [1], code, MONO_R_ARM64_BCC);
+ /* Load vtable slot addr */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
+ /* Load vtable slot */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
+ arm_brx (code, ARMREG_IP0);
+
+ /* No match */
+ mono_arm_patch (labels [2], code, MONO_R_ARM64_CBZ);
+ /* Load fail addr */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
+ arm_brx (code, ARMREG_IP0);
+
+ emit_code_bytes (acfg, buf, code - buf);
+
+ common_tramp_size = code - buf;
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT_THUNK] = common_tramp_size;
+
+ arm64_emit_tramp_page_specific_code (acfg, pagesize, common_tramp_size, specific_tramp_size);
+}
+
+static void
+arm64_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+ /* Load argument from second GOT slot */
+ arm64_emit_load_got_slot (acfg, ARMREG_R17, offset + 1);
+ /* Load generic trampoline address from first GOT slot */
+ arm64_emit_load_got_slot (acfg, ARMREG_R16, offset);
+ fprintf (acfg->fp, "br x16\n");
+ *tramp_size = 7 * 4;
+}
+
+static void
+arm64_emit_unbox_trampoline (MonoAotCompile *acfg, MonoCompile *cfg, MonoMethod *method, const char *call_target)
+{
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, "add x0, x0, %d\n", (int)(sizeof (MonoObject)));
+ fprintf (acfg->fp, "b %s\n", call_target);
+}
+
+static void
+arm64_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+ /* Similar to the specific trampolines, but use the rgctx reg instead of ip1 */
+
+ /* Load argument from first GOT slot */
+ g_assert (MONO_ARCH_RGCTX_REG == 27);
+ arm64_emit_load_got_slot (acfg, ARMREG_R27, offset);
+ /* Load generic trampoline address from second GOT slot */
+ arm64_emit_load_got_slot (acfg, ARMREG_R16, offset + 1);
+ fprintf (acfg->fp, "br x16\n");
+ *tramp_size = 7 * 4;
+}
+
+static void
+arm64_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+ guint8 buf [128];
+ guint8 *code, *labels [16];
+
+ /* Load parameter from GOT slot into ip1 */
+ arm64_emit_load_got_slot (acfg, ARMREG_R17, offset);
+
+ code = buf;
+ labels [0] = code;
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 0);
+ arm_cmpx (code, ARMREG_IP0, MONO_ARCH_RGCTX_REG);
+ labels [1] = code;
+ arm_bcc (code, ARMCOND_EQ, 0);
+
+ /* End-of-loop check */
+ labels [2] = code;
+ arm_cbzx (code, ARMREG_IP0, 0);
+
+ /* Loop footer */
+ arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 2 * 8);
+ arm_b (code, labels [0]);
+
+ /* Match */
+ mono_arm_patch (labels [1], code, MONO_R_ARM64_BCC);
+ /* Load vtable slot addr */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
+ /* Load vtable slot */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
+ arm_brx (code, ARMREG_IP0);
+
+ /* No match */
+ mono_arm_patch (labels [2], code, MONO_R_ARM64_CBZ);
+ /* Load fail addr */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP1, 8);
+ arm_brx (code, ARMREG_IP0);
+
+ emit_code_bytes (acfg, buf, code - buf);
+
+ *tramp_size = code - buf + (3 * 4);
+}
+
+static void
+arm64_emit_gsharedvt_arg_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+ /* Similar to the specific trampolines, but the address is in the second slot */
+ /* Load argument from first GOT slot */
+ arm64_emit_load_got_slot (acfg, ARMREG_R17, offset);
+ /* Load generic trampoline address from second GOT slot */
+ arm64_emit_load_got_slot (acfg, ARMREG_R16, offset + 1);
+ fprintf (acfg->fp, "br x16\n");
+ *tramp_size = 7 * 4;
+}
+
#endif
GPtrArray *patches;
MonoJumpInfo *patch_info;
MonoDebugSourceLocation **locs = NULL;
- gboolean skip;
+ gboolean skip, prologue_end = FALSE;
#ifdef MONO_ARCH_AOT_SUPPORTED
gboolean direct_call, external_call;
guint32 got_slot;
if (locs && locs [i]) {
MonoDebugSourceLocation *loc = locs [i];
int findex;
+ const char *options;
findex = get_file_index (acfg, loc->source_file);
emit_unset_mode (acfg);
- fprintf (acfg->fp, ".loc %d %d 0\n", findex, loc->row);
+ if (!prologue_end)
+ options = " prologue_end";
+ else
+ options = "";
+ prologue_end = TRUE;
+ fprintf (acfg->fp, ".loc %d %d 0%s\n", findex, loc->row, options);
mono_debug_symfile_free_location (loc);
}
//acfg->aot_opts.print_skipped_methods = TRUE;
-#if !defined(ENABLE_GSHAREDVT)
+#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
if (opts & MONO_OPT_GSHAREDVT) {
aot_printerrf (acfg, "-O=gsharedvt not supported on this platform.\n");
return 1;
#endif
if (acfg->aot_opts.llvm_only) {
-#ifndef ENABLE_GSHAREDVT
- aot_printerrf (acfg, "--aot=llvmonly requires a runtime compiled with --enable-gsharedvt.\n");
+#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
+ aot_printerrf (acfg, "--aot=llvmonly requires a runtime that supports gsharedvt.\n");
return 1;
#endif
}
-#if defined(ENABLE_GSHAREDVT) && defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
acfg->opts |= MONO_OPT_GSHAREDVT;
opts |= MONO_OPT_GSHAREDVT;
#endif
}
}
- if (acfg->aot_opts.dwarf_debug && acfg->aot_opts.asm_only && acfg->aot_opts.gnu_asm) {
+ if (acfg->aot_opts.dwarf_debug && acfg->aot_opts.gnu_asm) {
/*
* CLANG supports GAS .file/.loc directives, so emit line number information this way
- * FIXME: CLANG only emits line number info for .loc directives followed by assembly, not
- * .byte directives.
*/
- //acfg->gas_line_numbers = TRUE;
+ acfg->gas_line_numbers = TRUE;
}
if ((!acfg->aot_opts.nodebug || acfg->aot_opts.dwarf_debug) && acfg->has_jitted_code) {
aot_printerrf (acfg, "The dwarf AOT option requires the --debug option.\n");
return 1;
}
- acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE, !acfg->gas_line_numbers);
+ acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, !acfg->gas_line_numbers);
}
if (acfg->w)
* (C) 2002 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc.
* Copyright 2011 Xamarin, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
g_free (err);
- aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), MONO_ARCHITECTURE, g_path_get_basename (assembly->image->name), MONO_SOLIB_EXT);
+ g_free (aot_name);
+ char *basename = g_path_get_basename (assembly->image->name);
+ aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), MONO_ARCHITECTURE, basename, MONO_SOLIB_EXT);
+ g_free (basename);
sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
if (!sofile) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
mono_error_cleanup (&error); /* FIXME don't swallow the error */
}
- gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1);
+ gi->generic_sharing_context = alloc0_jit_info_data (domain, sizeof (MonoGenericSharingContext), async);
if (decode_value (p, &p)) {
/* gsharedvt */
MonoGenericSharingContext *gsctx = gi->generic_sharing_context;
#endif
-#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) && !defined(ENABLE_GSHAREDVT)
-
-gboolean
-mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
-{
- return FALSE;
-}
-
-gpointer
-mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
-{
- NOT_IMPLEMENTED;
- return NULL;
-}
-
-#endif
-
#ifndef MONO_ARCH_HAVE_DECOMPOSE_OPTS
void
mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
using System.Reflection;
/*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
* Regression tests for the mono JIT.
*
* Each test needs to be of the form:
*
* (C) 2005 Ximian, Inc. http://www.ximian.com
* Copyright 2011 Xamarin Inc. http://www.xamarin.com
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
# Copyright 2003-2011 Novell, Inc (http://www.novell.com)
# Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
# arm cpu description file
# this file is read by genmdesc to pruduce a table with all the relevant information
# about the cpu instructions that may be used by the regsiter allocator, the scheduler
# Copyright 2011-2013 Xamarin, Inc (http://www.xamarin.com)
# Copyright 2003-2011 Novell, Inc (http://www.novell.com)
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
# arm64 cpu description file
# this file is read by genmdesc to pruduce a table with all the relevant information
# about the cpu instructions that may be used by the regsiter allocator, the scheduler
*
* Copyright 2009-2010 Novell, Inc.
* Copyright 2011 Xamarin Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
} else if (type == VALUE_TYPE_ID_NULL) {
*(MonoObject**)addr = NULL;
} else if (type == MONO_TYPE_VALUETYPE) {
+ MonoError error;
guint8 *buf2;
gboolean is_enum;
MonoClass *klass;
g_free (vtype_buf);
return err;
}
- *(MonoObject**)addr = mono_value_box (d, klass, vtype_buf);
+ *(MonoObject**)addr = mono_value_box_checked (d, klass, vtype_buf, &error);
+ mono_error_cleanup (&error);
g_free (vtype_buf);
} else {
char *name = mono_type_full_name (t);
static ErrorCode
decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
{
+ MonoError error;
ErrorCode err;
int type = decode_byte (buf, &buf, limit);
g_free (nullable_buf);
return err;
}
- mono_nullable_init (addr, mono_value_box (domain, mono_class_from_mono_type (targ), nullable_buf), mono_class_from_mono_type (t));
+ MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type (targ), nullable_buf, &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error);
+ return ERR_INVALID_OBJECT;
+ }
+ mono_nullable_init (addr, boxed, mono_class_from_mono_type (t));
g_free (nullable_buf);
*endbuf = buf;
return ERR_NONE;
*
* (C) 2002 Ximian, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
*
* (C) 2003 Ximian, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <string.h>
#include <mono/metadata/debug-helpers.h>
*
* (C) 2002-2003 Ximian, Inc.
* (C) 2003-2006 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
GSList *cie_program;
FILE *fp;
const char *temp_prefix;
- gboolean emit_line, appending, collect_line_info;
+ gboolean emit_line;
GSList *line_info;
int cur_file_index;
};
* Create a DWARF writer object. WRITER is the underlying image writer this
* writer will emit to. IL_FILE is the file where IL code will be dumped to for
* methods which have no line number info. It can be NULL.
- * If APPENDING is TRUE, the output file will be in assembleable state after each
- * call to the _emit_ functions. This is used for XDEBUG. If APPENDING is FALSE,
- * a separate mono_dwarf_writer_close () call is needed to finish the emission of
- * debug information.
*/
MonoDwarfWriter*
-mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_start_line, gboolean appending, gboolean emit_line_numbers)
+mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_start_line, gboolean emit_line_numbers)
{
MonoDwarfWriter *w = g_new0 (MonoDwarfWriter, 1);
-
- /*
- * The appending flag is needed because we use subsections to order things in
- * the debug info, and:
- * - apple's assembler doesn't support them
- * - the binary writer has problems with subsections+alignment
- * So instead of subsections, we use the _close () function in AOT mode,
- * which writes out things in order.
- */
w->w = writer;
w->il_file = il_file;
w->il_file_line_index = il_file_start_line;
- w->appending = appending;
-
- if (appending)
- g_assert (mono_img_writer_subsections_supported (w->w));
-
- w->emit_line = TRUE;
-
- if (appending) {
- if (!mono_img_writer_subsections_supported (w->w))
- /* Can't emit line number info without subsections */
- w->emit_line = FALSE;
- } else {
- /* Collect line number info and emit it at once */
- w->collect_line_info = TRUE;
- }
- if (!emit_line_numbers) {
- w->emit_line = FALSE;
- w->collect_line_info = FALSE;
- }
+ w->emit_line = emit_line_numbers;
w->fp = mono_img_writer_get_fp (w->w);
w->temp_prefix = mono_img_writer_get_temp_label_prefix (w->w);
GSList *l;
GSList *info_list;
- g_assert (w->collect_line_info);
-
add_line_number_file_name (w, "<unknown>", 0, 0);
/* Collect files */
char *s, *build_info;
int i;
+ if (!w->emit_line) {
+ emit_section_change (w, ".debug_line", 0);
+ emit_label (w, ".Ldebug_line_section_start");
+ emit_label (w, ".Ldebug_line_start");
+ }
+
w->cie_program = base_unwind_program;
emit_section_change (w, ".debug_abbrev", 0);
emit_int32 (w, 0); /* .debug_abbrev offset */
emit_byte (w, sizeof (gpointer)); /* address size */
- if (mono_img_writer_subsections_supported (w->w) && w->appending) {
- /* Emit this into a separate section so it gets placed at the end */
- emit_section_change (w, ".debug_info", 1);
- emit_byte (w, 0); /* close COMPILE_UNIT */
- emit_label (w, ".Ldebug_info_end");
- emit_section_change (w, ".debug_info", 0);
- }
-
/* Compilation unit */
emit_uleb128 (w, ABBREV_COMPILE_UNIT);
build_info = mono_get_runtime_build_info ();
emit_pointer_value (w, 0);
emit_pointer_value (w, 0);
/* offset into .debug_line section */
- if (w->emit_line)
- emit_symbol_diff (w, ".Ldebug_line_start", ".Ldebug_line_section_start", 0);
- else
- emit_pointer_value (w, 0);
+ emit_symbol_diff (w, ".Ldebug_line_start", ".Ldebug_line_section_start", 0);
/* Base types */
for (i = 0; i < G_N_ELEMENTS (basic_types); ++i) {
void
mono_dwarf_writer_close (MonoDwarfWriter *w)
{
- if (!w->appending) {
- emit_section_change (w, ".debug_info", 0);
- emit_byte (w, 0); /* close COMPILE_UNIT */
- emit_label (w, ".Ldebug_info_end");
- }
+ emit_section_change (w, ".debug_info", 0);
+ emit_byte (w, 0); /* close COMPILE_UNIT */
+ emit_label (w, ".Ldebug_info_end");
- if (w->collect_line_info)
+ if (w->emit_line)
emit_all_line_number_info (w);
}
if (!prev_file_name || strcmp (loc->source_file, prev_file_name) != 0) {
/* Add an entry to the file table */
/* FIXME: Avoid duplicates */
- if (w->collect_line_info)
- file_index = get_line_number_file_name (w, loc->source_file) + 1;
- else
- file_index = emit_line_number_file_name (w, loc->source_file, 0, 0);
+ file_index = get_line_number_file_name (w, loc->source_file) + 1;
g_free (prev_file_name);
prev_file_name = g_strdup (loc->source_file);
w->fde_index ++;
}
- /* Emit line number info */
+ /* Save the information needed to emit the line number info later at once */
/* != could happen when using --regression */
if (debug_info && (debug_info->code_start == code)) {
- if (w->collect_line_info) {
- MethodLineNumberInfo *info;
-
- /* Save the information needed to emit the line number info later at once */
- info = g_new0 (MethodLineNumberInfo, 1);
- info->method = method;
- info->start_symbol = g_strdup (start_symbol);
- info->end_symbol = g_strdup (end_symbol);
- info->code = code;
- info->code_size = code_size;
- w->line_info = g_slist_prepend (w->line_info, info);
- } else {
- emit_line_number_info (w, method, start_symbol, end_symbol, code, code_size, debug_info);
- }
+ MethodLineNumberInfo *info;
+
+ info = g_new0 (MethodLineNumberInfo, 1);
+ info->method = method;
+ info->start_symbol = g_strdup (start_symbol);
+ info->end_symbol = g_strdup (end_symbol);
+ info->code = code;
+ info->code_size = code_size;
+ w->line_info = g_slist_prepend (w->line_info, info);
}
emit_line (w);
typedef struct _MonoDwarfWriter MonoDwarfWriter;
-MonoDwarfWriter* mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_start_line, gboolean appending, gboolean emit_line_numbers);
+MonoDwarfWriter* mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_start_line, gboolean emit_line_numbers);
void mono_dwarf_writer_destroy (MonoDwarfWriter *w);
*
* (C) 2001 Ximian, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
guint64 dummy5, guint64 dummy6,
MonoContext *mctx, MonoObject *exc, gboolean rethrow)
{
+ MonoError error;
MonoContext ctx;
/* mctx is on the caller's stack */
memcpy (&ctx, mctx, sizeof (MonoContext));
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
MonoException *mono_ex = (MonoException*)exc;
if (!rethrow) {
mono_ex->stack_trace = NULL;
mono_ex->trace_ips = NULL;
}
}
+ mono_error_assert_ok (&error);
/* adjust eip so that it point into the call instruction */
ctx.gregs [AMD64_RIP] --;
amd64_lea_membase (code, AMD64_RAX, AMD64_RSP, stack_size + sizeof(mgreg_t));
amd64_mov_membase_reg (code, AMD64_RSP, regs_offset + (AMD64_RSP * sizeof(mgreg_t)), X86_EAX, sizeof(mgreg_t));
/* Save IP */
- if (llvm_abs)
- amd64_alu_reg_reg (code, X86_XOR, AMD64_RAX, AMD64_RAX);
- else
- amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, stack_size, sizeof(mgreg_t));
+ amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, stack_size, sizeof(mgreg_t));
amd64_mov_membase_reg (code, AMD64_RSP, regs_offset + (AMD64_RIP * sizeof(mgreg_t)), AMD64_RAX, sizeof(mgreg_t));
/* Set arg1 == ctx */
amd64_lea_membase (code, AMD64_RAX, AMD64_RSP, ctx_offset);
if (resume_unwind) {
amd64_mov_membase_imm (code, AMD64_RSP, arg_offsets [2], 0, sizeof(mgreg_t));
} else if (corlib) {
- amd64_mov_membase_reg (code, AMD64_RSP, arg_offsets [2], AMD64_ARG_REG2, sizeof(mgreg_t));
if (llvm_abs)
- /*
- * The caller is LLVM code which passes the absolute address not a pc offset,
- * so compensate by passing 0 as 'rip' and passing the negated abs address as
- * the pc offset.
+ /*
+ * The caller doesn't pass in a pc/pc offset, instead we simply use the
+ * caller ip. Negate the pc adjustment done in mono_amd64_throw_corlib_exception ().
*/
- amd64_neg_membase (code, AMD64_RSP, arg_offsets [2]);
+ amd64_mov_membase_imm (code, AMD64_RSP, arg_offsets [2], 1, sizeof(mgreg_t));
+ else
+ amd64_mov_membase_reg (code, AMD64_RSP, arg_offsets [2], AMD64_ARG_REG2, sizeof(mgreg_t));
} else {
amd64_mov_membase_imm (code, AMD64_RSP, arg_offsets [2], rethrow, sizeof(mgreg_t));
}
void
mono_arm_throw_exception (MonoObject *exc, mgreg_t pc, mgreg_t sp, mgreg_t *int_regs, gdouble *fp_regs)
{
+ MonoError error;
MonoContext ctx;
gboolean rethrow = sp & 1;
memcpy (((guint8*)&ctx.regs) + (ARMREG_R4 * sizeof (mgreg_t)), int_regs, 8 * sizeof (mgreg_t));
memcpy (&ctx.fregs, fp_regs, sizeof (double) * 16);
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
MonoException *mono_ex = (MonoException*)exc;
if (!rethrow) {
mono_ex->stack_trace = NULL;
mono_ex->trace_ips = NULL;
}
}
+ mono_error_assert_ok (&error);
mono_handle_exception (&ctx, exc);
mono_restore_context (&ctx);
g_assert_not_reached ();
}
void
-mono_arm_throw_exception_by_token (guint32 type_token, mgreg_t pc, mgreg_t sp, mgreg_t *int_regs, gdouble *fp_regs)
+mono_arm_throw_exception_by_token (guint32 ex_token_index, mgreg_t pc, mgreg_t sp, mgreg_t *int_regs, gdouble *fp_regs)
{
+ guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
/* Clear thumb bit */
pc &= ~1;
- mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, type_token), pc, sp, int_regs, fp_regs);
+ mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, ex_token), pc, sp, int_regs, fp_regs);
}
void
/* exc is already in place in r0 */
if (corlib) {
/* The caller ip is already in R1 */
- if (llvm)
- /* Negate the ip adjustment done in mono_arm_throw_exception */
- ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
+ if (llvm) {
+ /*
+ * The address passed by llvm might point to before the call,
+ * thus outside the eh range recorded by llvm. Use the return
+ * address instead.
+ * FIXME: Do this on more platforms.
+ */
+ ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */
+ }
} else {
ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */
}
-#include "../../../mono-extensions/mono/mini/exceptions-arm64.c"
+/*
+ * exceptions-arm64.c: exception support for ARM64
+ *
+ * Copyright 2013 Xamarin Inc
+ *
+ * Based on exceptions-arm.c:
+ *
+ * Authors:
+ * Dietmar Maurer (dietmar@ximian.com)
+ * Paolo Molaro (lupus@ximian.com)
+ *
+ * (C) 2001 Ximian, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include "mini.h"
+
+#include <mono/arch/arm64/arm64-codegen.h>
+#include <mono/metadata/abi-details.h>
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+#ifndef DISABLE_JIT
+
+gpointer
+mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *start, *code;
+ MonoJumpInfo *ji = NULL;
+ GSList *unwind_ops = NULL;
+ int i, ctx_reg, size;
+
+ size = 256;
+ code = start = mono_global_codeman_reserve (size);
+
+ arm_movx (code, ARMREG_IP0, ARMREG_R0);
+ ctx_reg = ARMREG_IP0;
+ /* Restore fregs */
+ for (i = 0; i < 32; ++i)
+ arm_ldrfpx (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8));
+ /* Restore gregs */
+ // FIXME: Restore less registers
+ // FIXME: fp should be restored later
+ code = mono_arm_emit_load_regarray (code, 0xffffffff & ~(1 << ctx_reg) & ~(1 << ARMREG_SP), ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs));
+ /* ip0/ip1 doesn't need to be restored */
+ /* ip1 = pc */
+ arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, pc));
+ /* ip0 = sp */
+ arm_ldrx (code, ARMREG_IP0, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 8));
+ /* Restore sp, ctx is no longer valid */
+ arm_movspx (code, ARMREG_SP, ARMREG_IP0);
+ /* Branch to pc */
+ arm_brx (code, ARMREG_IP1);
+ /* Not reached */
+ arm_brk (code, 0);
+
+ g_assert ((code - start) < size);
+ mono_arch_flush_icache (start, code - start);
+ mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);
+
+ if (info)
+ *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops);
+
+ return start;
+}
+
+gpointer
+mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *code;
+ guint8* start;
+ int size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size;
+ MonoJumpInfo *ji = NULL;
+ GSList *unwind_ops = NULL;
+
+ size = 512;
+ start = code = mono_global_codeman_reserve (size);
+
+ /* Compute stack frame size and offsets */
+ offset = 0;
+ /* frame block */
+ offset += 2 * 8;
+ /* gregs */
+ gregs_offset = offset;
+ offset += 32 * 8;
+ /* fregs */
+ num_fregs = 8;
+ fregs_offset = offset;
+ offset += num_fregs * 8;
+ ctx_offset = offset;
+ ctx_offset += 8;
+ frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+
+ /*
+ * We are being called from C code, ctx is in r0, the address to call is in r1.
+ * We need to save state, restore ctx, make the call, then restore the previous state,
+ * returning the value returned by the call.
+ */
+
+ /* Setup a frame */
+ arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -frame_size);
+ arm_movspx (code, ARMREG_FP, ARMREG_SP);
+
+ /* Save ctx */
+ arm_strx (code, ARMREG_R0, ARMREG_FP, ctx_offset);
+ /* Save gregs */
+ code = mono_arm_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS | (1 << ARMREG_FP), ARMREG_FP, gregs_offset);
+ /* No need to save/restore fregs, since we don't currently use them */
+
+ /* Load regs from ctx */
+ code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs));
+ /* Load fp */
+ arm_ldrx (code, ARMREG_FP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 8));
+
+ /* Make the call */
+ arm_blrx (code, ARMREG_R1);
+ /* For filters, the result is in R0 */
+
+ /* Restore fp */
+ arm_ldrx (code, ARMREG_FP, ARMREG_SP, gregs_offset + (ARMREG_FP * 8));
+ /* Load ctx */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, ctx_offset);
+ /* Save registers back to ctx */
+ /* This isn't strictly neccessary since we don't allocate variables used in eh clauses to registers */
+ code = mono_arm_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoContext, regs));
+
+ /* Restore regs */
+ code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_FP, gregs_offset);
+ /* Destroy frame */
+ code = mono_arm_emit_destroy_frame (code, frame_size, (1 << ARMREG_IP0));
+ arm_retx (code, ARMREG_LR);
+
+ g_assert ((code - start) < size);
+ mono_arch_flush_icache (start, code - start);
+ mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);
+
+ if (info)
+ *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops);
+
+ return start;
+}
+
+static gpointer
+get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *start, *code;
+ MonoJumpInfo *ji = NULL;
+ GSList *unwind_ops = NULL;
+ int i, offset, gregs_offset, fregs_offset, frame_size, num_fregs;
+
+ code = start = mono_global_codeman_reserve (size);
+
+ /* We are being called by JITted code, the exception object/type token is in R0 */
+
+ /* Compute stack frame size and offsets */
+ offset = 0;
+ /* frame block */
+ offset += 2 * 8;
+ /* gregs */
+ gregs_offset = offset;
+ offset += 32 * 8;
+ /* fregs */
+ num_fregs = 8;
+ fregs_offset = offset;
+ offset += num_fregs * 8;
+ frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+
+ /* Setup a frame */
+ arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -frame_size);
+ arm_movspx (code, ARMREG_FP, ARMREG_SP);
+
+ /* Save gregs */
+ code = mono_arm_emit_store_regarray (code, 0xffffffff, ARMREG_FP, gregs_offset);
+ if (corlib && !llvm)
+ /* The real LR is in R1 */
+ arm_strx (code, ARMREG_R1, ARMREG_FP, gregs_offset + (ARMREG_LR * 8));
+ /* Save fp/sp */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, 0);
+ arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_FP * 8));
+ arm_addx_imm (code, ARMREG_IP0, ARMREG_FP, frame_size);
+ arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_SP * 8));
+ /* Save fregs */
+ for (i = 0; i < num_fregs; ++i)
+ arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));
+
+ /* Call the C trampoline function */
+ /* Arg1 = exception object/type token */
+ arm_movx (code, ARMREG_R0, ARMREG_R0);
+ /* Arg2 = caller ip */
+ if (corlib) {
+ if (llvm)
+ arm_ldrx (code, ARMREG_R1, ARMREG_FP, gregs_offset + (ARMREG_LR * 8));
+ else
+ arm_movx (code, ARMREG_R1, ARMREG_R1);
+ } else {
+ arm_ldrx (code, ARMREG_R1, ARMREG_FP, 8);
+ }
+ /* Arg 3 = gregs */
+ arm_addx_imm (code, ARMREG_R2, ARMREG_FP, gregs_offset);
+ /* Arg 4 = fregs */
+ arm_addx_imm (code, ARMREG_R3, ARMREG_FP, fregs_offset);
+ /* Arg 5 = corlib */
+ arm_movzx (code, ARMREG_R4, corlib ? 1 : 0, 0);
+ /* Arg 6 = rethrow */
+ arm_movzx (code, ARMREG_R5, rethrow ? 1 : 0, 0);
+ /* Call the function */
+ if (aot) {
+ const char *icall_name;
+
+ if (resume_unwind)
+ icall_name = "mono_arm_resume_unwind";
+ else
+ icall_name = "mono_arm_throw_exception";
+
+ code = mono_arm_emit_aotconst (&ji, code, start, ARMREG_LR, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
+ } else {
+ gpointer icall_func;
+
+ if (resume_unwind)
+ icall_func = mono_arm_resume_unwind;
+ else
+ icall_func = mono_arm_throw_exception;
+
+ code = mono_arm_emit_imm64 (code, ARMREG_LR, (guint64)icall_func);
+ }
+ arm_blrx (code, ARMREG_LR);
+ /* This shouldn't return */
+ arm_brk (code, 0x0);
+
+ g_assert ((code - start) < size);
+ mono_arch_flush_icache (start, code - start);
+ mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);
+
+ if (info)
+ *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops);
+
+ return start;
+}
+
+gpointer
+mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
+{
+ return get_throw_trampoline (256, FALSE, FALSE, FALSE, FALSE, "throw_exception", info, aot);
+}
+
+gpointer
+mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
+{
+ return get_throw_trampoline (256, FALSE, TRUE, FALSE, FALSE, "rethrow_exception", info, aot);
+}
+
+gpointer
+mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
+{
+ return get_throw_trampoline (256, TRUE, FALSE, FALSE, FALSE, "throw_corlib_exception", info, aot);
+}
+
+GSList*
+mono_arm_get_exception_trampolines (gboolean aot)
+{
+ MonoTrampInfo *info;
+ GSList *tramps = NULL;
+
+ /* LLVM uses the normal trampolines, but with a different name */
+ get_throw_trampoline (256, TRUE, FALSE, FALSE, FALSE, "llvm_throw_corlib_exception_trampoline", &info, aot);
+ tramps = g_slist_prepend (tramps, info);
+
+ get_throw_trampoline (256, TRUE, FALSE, TRUE, FALSE, "llvm_throw_corlib_exception_abs_trampoline", &info, aot);
+ tramps = g_slist_prepend (tramps, info);
+
+ get_throw_trampoline (256, FALSE, FALSE, FALSE, TRUE, "llvm_resume_unwind_trampoline", &info, aot);
+ tramps = g_slist_prepend (tramps, info);
+
+ return tramps;
+}
+
+#else /* DISABLE_JIT */
+
+gpointer
+mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+GSList*
+mono_arm_get_exception_trampolines (gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif /* !DISABLE_JIT */
+
+void
+mono_arch_exceptions_init (void)
+{
+ guint8 *tramp;
+ GSList *tramps, *l;
+
+ if (mono_aot_only) {
+ tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_trampoline");
+ mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE);
+ tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_abs_trampoline");
+ mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_abs_trampoline", NULL, TRUE);
+ tramp = mono_aot_get_trampoline ("llvm_resume_unwind_trampoline");
+ mono_register_jit_icall (tramp, "llvm_resume_unwind_trampoline", NULL, TRUE);
+ } else {
+ tramps = mono_arm_get_exception_trampolines (FALSE);
+ for (l = tramps; l; l = l->next) {
+ MonoTrampInfo *info = l->data;
+
+ mono_register_jit_icall (info->code, g_strdup (info->name), NULL, TRUE);
+ mono_tramp_info_register (info, NULL);
+ }
+ g_slist_free (tramps);
+ }
+}
+
+/*
+ * mono_arm_throw_exception:
+ *
+ * This function is called by the exception trampolines.
+ * FP_REGS points to the 8 callee saved fp regs.
+ */
+void
+mono_arm_throw_exception (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp_regs, gboolean corlib, gboolean rethrow)
+{
+ MonoError error;
+ MonoContext ctx;
+ MonoObject *exc = NULL;
+ guint32 ex_token_index, ex_token;
+
+ if (!corlib)
+ exc = arg;
+ else {
+ ex_token_index = (guint64)arg;
+ ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
+ exc = (MonoObject*)mono_exception_from_token (mono_defaults.corlib, ex_token);
+ }
+
+ /* Adjust pc so it points into the call instruction */
+ pc -= 4;
+
+ /* Initialize a ctx based on the arguments */
+ memset (&ctx, 0, sizeof (MonoContext));
+ memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32);
+ memcpy (&(ctx.fregs [ARMREG_D8]), fp_regs, sizeof (double) * 8);
+ ctx.pc = pc;
+
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
+ MonoException *mono_ex = (MonoException*)exc;
+ if (!rethrow)
+ mono_ex->stack_trace = NULL;
+ }
+ mono_error_assert_ok (&error);
+
+ mono_handle_exception (&ctx, exc);
+
+ mono_restore_context (&ctx);
+}
+
+void
+mono_arm_resume_unwind (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp_regs, gboolean corlib, gboolean rethrow)
+{
+ MonoContext ctx;
+
+ /* Adjust pc so it points into the call instruction */
+ pc -= 4;
+
+ /* Initialize a ctx based on the arguments */
+ memset (&ctx, 0, sizeof (MonoContext));
+ memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32);
+ memcpy (&(ctx.fregs [ARMREG_D8]), fp_regs, sizeof (double) * 8);
+ ctx.pc = pc;
+
+ mono_resume_unwind (&ctx);
+}
+
+/*
+ * mono_arch_unwind_frame:
+ *
+ * See exceptions-amd64.c for docs;
+ */
+gboolean
+mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
+ MonoJitInfo *ji, MonoContext *ctx,
+ MonoContext *new_ctx, MonoLMF **lmf,
+ mgreg_t **save_locations,
+ StackFrameInfo *frame)
+{
+ gpointer ip = MONO_CONTEXT_GET_IP (ctx);
+
+ memset (frame, 0, sizeof (StackFrameInfo));
+ frame->ji = ji;
+
+ *new_ctx = *ctx;
+
+ if (ji != NULL) {
+ mgreg_t regs [MONO_MAX_IREGS + 8 + 1];
+ guint8 *cfa;
+ guint32 unwind_info_len;
+ guint8 *unwind_info;
+
+ frame->type = FRAME_TYPE_MANAGED;
+
+ unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);
+
+ memcpy (regs, &new_ctx->regs, sizeof (mgreg_t) * 32);
+ /* v8..v15 are callee saved */
+ memcpy (regs + MONO_MAX_IREGS, &(new_ctx->fregs [8]), sizeof (mgreg_t) * 8);
+
+ mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start,
+ (guint8*)ji->code_start + ji->code_size,
+ ip, NULL, regs, MONO_MAX_IREGS + 8,
+ save_locations, MONO_MAX_IREGS, &cfa);
+
+ memcpy (&new_ctx->regs, regs, sizeof (mgreg_t) * 32);
+ memcpy (&(new_ctx->fregs [8]), regs + MONO_MAX_IREGS, sizeof (mgreg_t) * 8);
+
+ new_ctx->pc = regs [ARMREG_LR];
+ new_ctx->regs [ARMREG_SP] = (mgreg_t)cfa;
+
+ if (*lmf && (*lmf)->gregs [MONO_ARCH_LMF_REG_SP] && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->gregs [MONO_ARCH_LMF_REG_SP])) {
+ /* remove any unused lmf */
+ *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
+ }
+
+ /* we substract 1, so that the IP points into the call instruction */
+ new_ctx->pc--;
+
+ return TRUE;
+ } else if (*lmf) {
+ if (((gsize)(*lmf)->previous_lmf) & 2) {
+ /*
+ * This LMF entry is created by the soft debug code to mark transitions to
+ * managed code done during invokes.
+ */
+ MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
+
+ g_assert (ext->debugger_invoke);
+
+ memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
+
+ *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
+
+ frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
+
+ return TRUE;
+ }
+
+ frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
+
+ ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->pc, NULL);
+ if (!ji)
+ return FALSE;
+
+ g_assert (MONO_ARCH_LMF_REGS == ((0x3ff << 19) | (1 << ARMREG_FP) | (1 << ARMREG_SP)));
+ memcpy (&new_ctx->regs [ARMREG_R19], &(*lmf)->gregs [0], sizeof (mgreg_t) * 10);
+ new_ctx->regs [ARMREG_FP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_FP];
+ new_ctx->regs [ARMREG_SP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_SP];
+ new_ctx->pc = (*lmf)->pc;
+
+ /* we substract 1, so that the IP points into the call instruction */
+ new_ctx->pc--;
+
+ *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
+{
+ mono_sigctx_to_monoctx (sigctx, mctx);
+}
+
+void
+mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
+{
+ mono_monoctx_to_sigctx (mctx, sigctx);
+}
+
+/*
+ * handle_exception:
+ *
+ * Called by resuming from a signal handler.
+ */
+static void
+handle_signal_exception (gpointer obj)
+{
+ MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+ MonoContext ctx;
+
+ memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
+
+ mono_handle_exception (&ctx, obj);
+
+ mono_restore_context (&ctx);
+}
+
+/*
+ * This is the function called from the signal handler
+ */
+gboolean
+mono_arch_handle_exception (void *ctx, gpointer obj)
+{
+#if defined(MONO_CROSS_COMPILE)
+ g_assert_not_reached ();
+#else
+ MonoJitTlsData *jit_tls;
+ void *sigctx = ctx;
+
+ /*
+ * Resume into the normal stack and handle the exception there.
+ */
+ jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+
+ /* Pass the ctx parameter in TLS */
+ mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
+ /* The others in registers */
+ UCONTEXT_REG_R0 (sigctx) = (gsize)obj;
+
+ UCONTEXT_REG_PC (sigctx) = (gsize)handle_signal_exception;
+ UCONTEXT_REG_SP (sigctx) = UCONTEXT_REG_SP (sigctx) - MONO_ARCH_REDZONE_SIZE;
+#endif
+
+ return TRUE;
+}
+
+gpointer
+mono_arch_ip_from_context (void *sigctx)
+{
+#ifdef MONO_CROSS_COMPILE
+ g_assert_not_reached ();
+ return NULL;
+#else
+ return (gpointer)UCONTEXT_REG_PC (sigctx);
+#endif
+}
+
+void
+mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
+{
+ mgreg_t sp = (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
+
+ // FIXME:
+ g_assert (!user_data);
+
+ /* Allocate a stack frame */
+ sp -= 32;
+ MONO_CONTEXT_SET_SP (ctx, sp);
+
+ mono_arch_setup_resume_sighandler_ctx (ctx, async_cb);
+}
+
+/*
+ * mono_arch_setup_resume_sighandler_ctx:
+ *
+ * Setup CTX so execution continues at FUNC.
+ */
+void
+mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func)
+{
+ MONO_CONTEXT_SET_IP (ctx,func);
+}
throw_exception (MonoObject *exc, guint64 rethrow)
{
unw_context_t unw_ctx;
+ MonoError error;
MonoContext ctx;
MonoJitInfo *ji;
unw_word_t ip, sp;
int res;
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
MonoException *mono_ex = (MonoException*)exc;
if (!rethrow) {
mono_ex->stack_trace = NULL;
mono_ex->trace_ips = NULL;
}
}
+ mono_error_assert_ok (&error);
res = unw_getcontext (&unw_ctx);
g_assert (res == 0);
static void
throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gboolean rethrow)
{
+ MonoError error;
MonoContext ctx;
#ifdef DEBUG_EXCEPTIONS
memset (&ctx.sc_fpregs, 0, sizeof (mips_freg) * MONO_SAVED_FREGS);
MONO_CONTEXT_SET_IP (&ctx, eip);
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
MonoException *mono_ex = (MonoException*)exc;
if (!rethrow) {
mono_ex->stack_trace = NULL;
mono_ex->trace_ips = NULL;
}
}
+ mono_error_assert_ok (&error);
mono_handle_exception (&ctx, exc);
#ifdef DEBUG_EXCEPTIONS
g_print ("throw_exception: restore to pc=%p sp=%p fp=%p ctx=%p\n",
void
mono_ppc_throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, mgreg_t *int_regs, gdouble *fp_regs, gboolean rethrow)
{
+ MonoError error;
MonoContext ctx;
/* adjust eip so that it point into the call instruction */
memcpy (&ctx.regs, int_regs, sizeof (mgreg_t) * MONO_SAVED_GREGS);
memcpy (&ctx.fregs, fp_regs, sizeof (double) * MONO_SAVED_FREGS);
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
MonoException *mono_ex = (MonoException*)exc;
if (!rethrow) {
mono_ex->stack_trace = NULL;
mono_ex->trace_ips = NULL;
}
}
+ mono_error_assert_ok (&error);
mono_handle_exception (&ctx, exc);
mono_restore_context (&ctx);
/* Dietmar Maurer (dietmar@ximian.com) */
/* */
/* Copyright - 2001 Ximian, Inc. */
+/* Licensed under the MIT license. See LICENSE file in the project root for full license information. */
/* */
/*------------------------------------------------------------------*/
gulong *int_regs, gdouble *fp_regs, gint32 *acc_regs,
guint fpc, gboolean rethrow)
{
+ MonoError error;
MonoContext ctx;
int iReg;
MONO_CONTEXT_SET_BP (&ctx, sp);
MONO_CONTEXT_SET_IP (&ctx, ip);
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
MonoException *mono_ex = (MonoException*)exc;
if (!rethrow) {
mono_ex->stack_trace = NULL;
mono_ex->trace_ips = NULL;
}
}
+ mono_error_assert_ok (&error);
// mono_arch_handle_exception (&ctx, exc, FALSE);
mono_handle_exception (&ctx, exc);
mono_restore_context(&ctx);
static void
throw_exception (MonoObject *exc, gpointer sp, gpointer ip, gboolean rethrow)
{
+ MonoError error;
MonoContext ctx;
static void (*restore_context) (MonoContext *);
gpointer *window;
ctx.ip = ip;
ctx.fp = (gpointer*)(MONO_SPARC_WINDOW_ADDR (sp) [sparc_i6 - 16]);
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
MonoException *mono_ex = (MonoException*)exc;
if (!rethrow) {
mono_ex->stack_trace = NULL;
mono_ex->trace_ips = NULL;
}
}
+ mono_error_assert_ok (&error);
mono_handle_exception (&ctx, exc);
restore_context (&ctx);
mono_x86_throw_exception (mgreg_t *regs, MonoObject *exc,
mgreg_t eip, gboolean rethrow)
{
+ MonoError error;
MonoContext ctx;
ctx.esp = regs [X86_ESP];
g_assert ((ctx.esp % MONO_ARCH_FRAME_ALIGNMENT) == 0);
#endif
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
MonoException *mono_ex = (MonoException*)exc;
if (!rethrow) {
mono_ex->stack_trace = NULL;
mono_ex->trace_ips = NULL;
}
}
+ mono_error_assert_ok (&error);
/* adjust eip so that it point into the call instruction */
ctx.eip -= 1;
return 0;
}
+ interface ISmallArg {
+ T foo<T> (string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8,
+ string s9, string s10, string s11, string s12, string s13, T t);
+ }
+
+ class SmallArgClass : ISmallArg {
+ public T foo<T> (string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8,
+ string s9, string s10, string s11, string s12, string s13, T t) {
+ return t;
+ }
+ }
+
+ public static int test_1_small_gsharedvt_stack_arg_ios () {
+ ISmallArg o = new SmallArgClass ();
+ return o.foo<int> ("", "", "", "", "", "", "", "", "", "", "", "", "", 1);
+ }
+
// Passing vtype normal arguments on the stack
public static int test_0_arm64_vtype_stack_args () {
IFoo3<EmptyStruct> o = (IFoo3<EmptyStruct>)Activator.CreateInstance (typeof (Foo3<>).MakeGenericType (new Type [] { typeof (EmptyStruct) }));
static void
asm_writer_emit_start (MonoImageWriter *acfg)
{
+#if defined(TARGET_ASM_APPLE)
+ fprintf (acfg->fp, ".subsections_via_symbols\n");
+#endif
}
static int
* (C) 2002 Ximian, Inc.
* Copyright 2003-2011 Novell Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <math.h>
void
mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
{
+ MonoError error;
if (!array) {
mono_set_pending_exception (mono_get_exception_null_reference ());
return;
}
- if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
+ if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
+ if (mono_error_set_pending_exception (&error))
+ return;
mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
return;
}
MonoObject*
mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
{
+ MonoError error;
MonoJitTlsData *jit_tls = NULL;
MonoClass *oklass;
oklass = obj->vtable->klass;
if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
return obj;
- if (mono_object_isinst (obj, klass))
+ if (mono_object_isinst_checked (obj, klass, &error))
return obj;
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
if (mini_get_debug_options ()->better_cast_details) {
jit_tls->class_cast_from = oklass;
MonoObject*
mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
{
+ MonoError error;
MonoJitTlsData *jit_tls = NULL;
gpointer cached_vtable, obj_vtable;
if (cached_vtable == obj_vtable)
return obj;
- if (mono_object_isinst (obj, klass)) {
+ if (mono_object_isinst_checked (obj, klass, &error)) {
*cache = obj_vtable;
return obj;
}
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
if (mini_get_debug_options ()->better_cast_details) {
jit_tls->class_cast_from = obj->vtable->klass;
MonoObject*
mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
{
+ MonoError error;
size_t cached_vtable, obj_vtable;
if (!obj)
return (cached_vtable & 0x1) ? NULL : obj;
}
- if (mono_object_isinst (obj, klass)) {
+ if (mono_object_isinst_checked (obj, klass, &error)) {
*cache = (gpointer)obj_vtable;
return obj;
} else {
+ if (mono_error_set_pending_exception (&error))
+ return NULL;
/*negative cache*/
*cache = (gpointer)(obj_vtable | 0x1);
return NULL;
/*
* Calling a non-vtype method with a vtype receiver, has to box.
*/
- *this_arg = mono_value_box (mono_domain_get (), klass, mp);
+ *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
else if (klass->valuetype)
/*
* Calling a vtype method with a vtype receiver
*
* (C) 2002 Ximian, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
// (C) 2009-2011 Novell, Inc.
// Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
//
-
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// Mono's internal header files are not C++ clean, so avoid including them if
// possible
*
* (C) 2006 Novell, Inc. http://www.novell.com
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* (C) 2002 Ximian, Inc.
* Copyright 2003-2010 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
skip_dead_blocks = !dont_verify;
if (skip_dead_blocks) {
- original_bb = bb = mono_basic_block_split (method, &cfg->error);
+ original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
CHECK_CFG_ERROR;
g_assert (bb);
}
INLINE_FAILURE ("class init");
if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
- g_assert_not_reached ();
goto exception_exit;
}
}
--- /dev/null
+/*
+ * mini-amd64-gsharedvt.c: libcorkscrew-based native unwinder
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ * Rodrigo Kumpera <kumpera@gmail.com>
+ * Andi McClure <andi.mcclure@xamarin.com>
+ *
+ * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/abi-details.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
+#include <mono/metadata/tabledefs.h>
+#include <mono/metadata/mono-debug-debugger.h>
+#include <mono/metadata/profiler-private.h>
+#include <mono/metadata/gc-internals.h>
+#include <mono/arch/amd64/amd64-codegen.h>
+
+#include <mono/utils/memcheck.h>
+
+#include "mini.h"
+#include "mini-amd64.h"
+#include "mini-amd64-gsharedvt.h"
+#include "debugger-agent.h"
+
+#if defined (MONO_ARCH_GSHAREDVT_SUPPORTED)
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+gboolean
+mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
+{
+ return FALSE;
+}
+
+static const char*
+storage_name (ArgStorage st)
+{
+ switch (st) {
+ case ArgInIReg: return "ArgInIReg";
+ case ArgInFloatSSEReg: return "ArgInFloatSSEReg";
+ case ArgInDoubleSSEReg: return "ArgInDoubleSSEReg";
+ case ArgOnStack: return "ArgOnStack";
+ case ArgValuetypeInReg: return "ArgValuetypeInReg";
+ case ArgValuetypeAddrInIReg: return "ArgValuetypeAddrInIReg";
+ case ArgGSharedVtInReg: return "ArgGSharedVtInReg";
+ case ArgGSharedVtOnStack: return "ArgGSharedVtOnStack";
+ case ArgNone: return "ArgNone";
+ default: return "unknown";
+ }
+}
+
+static char *
+arg_info_desc (ArgInfo *info)
+{
+ GString *str = g_string_new ("");
+
+ g_string_append_printf (str, "offset %d reg %s storage %s nregs %d", info->offset, mono_arch_regname (info->reg), storage_name (info->storage), info->nregs);
+ if (info->storage == ArgValuetypeInReg)
+ g_string_append_printf (str, " {(%s %s), (%s %s)",
+ storage_name (info->pair_storage [0]),
+ mono_arch_regname (info->pair_regs [0]),
+ storage_name (info->pair_storage [1]),
+ mono_arch_regname (info->pair_regs [1]));
+
+ return g_string_free (str, FALSE);
+}
+
+static inline void
+add_to_map (GPtrArray *map, int src, int dst)
+{
+ g_ptr_array_add (map, GUINT_TO_POINTER (src));
+ g_ptr_array_add (map, GUINT_TO_POINTER (dst));
+}
+
+/*
+ * Slot mapping:
+ * 0..5 - rdi, rsi, rdx, rcx, r8, r9
+ * 6..13 - xmm0..xmm7
+ * 14.. - stack slots
+ */
+static inline int
+map_reg (int reg)
+{
+ int i = 0;
+ for (i = 0; i < PARAM_REGS; ++i) {
+ if (param_regs [i] == reg)
+ return i;
+ }
+ g_error ("Invalid argument register number %d", reg);
+ return -1;
+}
+
+static inline int
+map_freg (int reg)
+{
+ return reg + PARAM_REGS;
+}
+
+static inline int
+map_stack_slot (int slot)
+{
+ return slot + PARAM_REGS + FLOAT_PARAM_REGS;
+}
+
+/*
+Format for the source descriptor:
+
+
+Format for the destination descriptor:
+ bits 0:15 - source register
+ bits 16:23 - return marshal
+ bits 24:32 - slot count
+*/
+#define SRC_DESCRIPTOR_MARSHAL_SHIFT 16
+#define SRC_DESCRIPTOR_MARSHAL_MASK 0x0Ff
+
+#define SLOT_COUNT_SHIFT 24
+#define SLOT_COUNT_MASK 0xff
+#define SLOT_BYTE_SIZE 8
+
+static int
+get_arg_slots (ArgInfo *ainfo, int **out_slots, gboolean is_source_argument)
+{
+ int sreg = ainfo->reg;
+ int sslot = ainfo->offset / 8;
+ int *src = NULL;
+ int i, nsrc;
+
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ nsrc = 1;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_reg (sreg);
+ break;
+ case ArgValuetypeInReg:
+ nsrc = ainfo->nregs;
+ src = g_malloc (nsrc * sizeof (int));
+ for (i = 0; i < ainfo->nregs; ++i)
+ src [i] = map_reg (ainfo->pair_regs [i]);
+ break;
+ case ArgOnStack:
+ nsrc = ainfo->arg_size / SLOT_BYTE_SIZE;
+ src = g_malloc (nsrc * sizeof (int));
+ // is_source_argument adds 2 because we're skipping over the old BBP and the return address
+ // XXX this is a very fragile setup as changes in alignment for the caller reg array can cause the magic number be 3
+ for (i = 0; i < nsrc; ++i)
+ src [i] = map_stack_slot (sslot + i + (is_source_argument ? 2 : 0));
+ break;
+ case ArgInDoubleSSEReg:
+ case ArgInFloatSSEReg:
+ nsrc = 1;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_freg (sreg);
+ break;
+ default:
+ NOT_IMPLEMENTED;
+ break;
+ }
+
+ *out_slots = src;
+ return nsrc;
+}
+
+// Once src is known, operate on the dst
+static void
+handle_marshal_when_src_gsharedvt (ArgInfo *dst_info, int *arg_marshal, int *arg_slots)
+{
+ switch (dst_info->storage) {
+ case ArgInIReg:
+ case ArgInDoubleSSEReg:
+ case ArgInFloatSSEReg:
+ *arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL;
+ *arg_slots = 1;
+ break;
+ case ArgOnStack:
+ *arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL;
+ g_assert (dst_info->arg_size % SLOT_BYTE_SIZE == 0); // Assert quadword aligned
+ *arg_slots = dst_info->arg_size / SLOT_BYTE_SIZE;
+ break;
+ case ArgValuetypeInReg:
+ *arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL;
+ *arg_slots = dst_info->nregs;
+ break;
+ default:
+ NOT_IMPLEMENTED; // Inappropriate value: if dst and src are gsharedvt at once, we shouldn't be here
+ break;
+ }
+}
+
+// Once dst is known, operate on the src
+static void
+handle_marshal_when_dst_gsharedvt (ArgInfo *src_info, int *arg_marshal)
+{
+ switch (src_info->storage) {
+ case ArgInIReg:
+ case ArgInDoubleSSEReg:
+ case ArgInFloatSSEReg:
+ case ArgValuetypeInReg:
+ case ArgOnStack:
+ *arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
+ break;
+ default:
+ NOT_IMPLEMENTED; // See above
+ break;
+ }
+}
+
+static void
+handle_map_when_gsharedvt_in_reg (ArgInfo *reg_info, int *n, int **map)
+{
+ *n = 1;
+ *map = g_new0 (int, 1);
+ (*map) [0] = map_reg (reg_info->reg);
+}
+
+static void
+handle_map_when_gsharedvt_on_stack (ArgInfo *reg_info, int *n, int **map, gboolean is_source_argument)
+{
+ *n = 1;
+ *map = g_new0 (int, 1);
+ int sslot = reg_info->offset / SLOT_BYTE_SIZE;
+ (*map) [0] = map_stack_slot (sslot + (is_source_argument ? 2 : 0)); // see get_arg_slots
+}
+
+gpointer
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
+{
+ GSharedVtCallInfo *info;
+ CallInfo *caller_cinfo, *callee_cinfo;
+ MonoMethodSignature *caller_sig, *callee_sig;
+ int aindex, i;
+ gboolean var_ret = FALSE;
+ CallInfo *cinfo, *gcinfo;
+ MonoMethodSignature *sig, *gsig;
+ GPtrArray *map;
+
+ if (gsharedvt_in) {
+ caller_sig = normal_sig;
+ callee_sig = gsharedvt_sig;
+ caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+ callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+ } else {
+ callee_sig = normal_sig;
+ caller_sig = gsharedvt_sig;
+ callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+ caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+ }
+
+ /*
+ * If GSHAREDVT_IN is true, this means we are transitioning from normal to gsharedvt code. The caller uses the
+ * normal call signature, while the callee uses the gsharedvt signature.
+ * If GSHAREDVT_IN is false, its the other way around.
+ */
+
+ /* sig/cinfo describes the normal call, while gsig/gcinfo describes the gsharedvt call */
+ if (gsharedvt_in) {
+ sig = caller_sig;
+ gsig = callee_sig;
+ cinfo = caller_cinfo;
+ gcinfo = callee_cinfo;
+ } else {
+ sig = callee_sig;
+ gsig = caller_sig;
+ cinfo = callee_cinfo;
+ gcinfo = caller_cinfo;
+ }
+
+ DEBUG_AMD64_GSHAREDVT_PRINT ("source sig: (%s) return (%s)\n", mono_signature_get_desc (caller_sig, FALSE), mono_type_full_name (mono_signature_get_return_type (caller_sig))); // Leak
+ DEBUG_AMD64_GSHAREDVT_PRINT ("dest sig: (%s) return (%s)\n", mono_signature_get_desc (callee_sig, FALSE), mono_type_full_name (mono_signature_get_return_type (callee_sig)));
+
+ if (gcinfo->ret.is_gsharedvt_return_value) {
+ /*
+ * The return type is gsharedvt
+ */
+ var_ret = TRUE;
+ }
+
+ /*
+ * The stack looks like this:
+ * <arguments>
+ * <trampoline frame>
+ * <call area>
+ * We have to map the stack slots in <arguments> to the stack slots in <call area>.
+ */
+ map = g_ptr_array_new ();
+
+ for (aindex = 0; aindex < cinfo->nargs; ++aindex) {
+ ArgInfo *src_info = &caller_cinfo->args [aindex];
+ ArgInfo *dst_info = &callee_cinfo->args [aindex];
+ int *src = NULL, *dst = NULL;
+ int nsrc = -1, ndst = -1, nslots = 0;
+
+ int arg_marshal = GSHAREDVT_ARG_NONE;
+ int arg_slots = 0; // Size in quadwords
+ DEBUG_AMD64_GSHAREDVT_PRINT ("-- arg %d in (%s) out (%s)\n", aindex, arg_info_desc (src_info), arg_info_desc (dst_info));
+
+ switch (src_info->storage) {
+ case ArgInIReg:
+ case ArgInDoubleSSEReg:
+ case ArgInFloatSSEReg:
+ case ArgValuetypeInReg:
+ case ArgOnStack:
+ nsrc = get_arg_slots (src_info, &src, TRUE);
+ break;
+ case ArgGSharedVtInReg:
+ handle_marshal_when_src_gsharedvt (dst_info, &arg_marshal, &arg_slots);
+ handle_map_when_gsharedvt_in_reg (src_info, &nsrc, &src);
+ break;
+ case ArgGSharedVtOnStack:
+ handle_marshal_when_src_gsharedvt (dst_info, &arg_marshal, &arg_slots);
+ handle_map_when_gsharedvt_on_stack (src_info, &nsrc, &src, TRUE);
+ break;
+ default:
+ g_error ("Gsharedvt can't handle source arg type %d", (int)src_info->storage); // Inappropriate value: ArgValuetypeAddrInIReg is for returns only
+ }
+
+ switch (dst_info->storage) {
+ case ArgInIReg:
+ case ArgInDoubleSSEReg:
+ case ArgInFloatSSEReg:
+ case ArgOnStack:
+ case ArgValuetypeInReg:
+ ndst = get_arg_slots (dst_info, &dst, FALSE);
+ break;
+ case ArgGSharedVtInReg:
+ handle_marshal_when_dst_gsharedvt (src_info, &arg_marshal);
+ handle_map_when_gsharedvt_in_reg (dst_info, &ndst, &dst);
+ break;
+ case ArgGSharedVtOnStack:
+ handle_marshal_when_dst_gsharedvt (src_info, &arg_marshal);
+ handle_map_when_gsharedvt_on_stack (dst_info, &ndst, &dst, FALSE);
+ break;
+ default:
+ g_error ("Gsharedvt can't handle dest arg type %d", (int)dst_info->storage); // See above
+ }
+ if (nsrc)
+ src [0] |= (arg_marshal << SRC_DESCRIPTOR_MARSHAL_SHIFT) | (arg_slots << SLOT_COUNT_SHIFT);
+
+ /* Merge and add to the global list*/
+ nslots = MIN (nsrc, ndst);
+ DEBUG_AMD64_GSHAREDVT_PRINT ("nsrc %d ndst %d\n", nsrc, ndst);
+
+ for (i = 0; i < nslots; ++i)
+ add_to_map (map, src [i], dst [i]);
+
+ g_free (src);
+ g_free (dst);
+ }
+
+ DEBUG_AMD64_GSHAREDVT_PRINT ("-- return in (%s) out (%s) var_ret %d\n", arg_info_desc (&caller_cinfo->ret), arg_info_desc (&callee_cinfo->ret), var_ret);
+
+ if (cinfo->ret.storage == ArgValuetypeAddrInIReg) {
+ /* Both the caller and the callee pass the vtype ret address in r8 */
+ g_assert (cinfo->ret.storage == gcinfo->ret.storage);
+ add_to_map (map, map_reg (cinfo->ret.reg), map_reg (cinfo->ret.reg));
+ }
+
+ info = mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo) + (map->len * sizeof (int)));
+ info->addr = addr;
+ info->stack_usage = callee_cinfo->stack_usage;
+ info->ret_marshal = GSHAREDVT_RET_NONE;
+ info->gsharedvt_in = gsharedvt_in ? 1 : 0;
+ info->vret_slot = -1;
+ info->calli = calli;
+
+ if (var_ret) {
+ g_assert (gcinfo->ret.is_gsharedvt_return_value);
+ info->vret_arg_reg = map_reg (gcinfo->ret.reg);
+ DEBUG_AMD64_GSHAREDVT_PRINT ("mapping vreg_arg_reg to %d in reg %s\n", info->vret_arg_reg, mono_arch_regname (gcinfo->ret.reg));
+ } else {
+ info->vret_arg_reg = -1;
+ }
+
+#ifdef DEBUG_AMD64_GSHAREDVT
+ printf ("final map:\n");
+ for (i = 0; i < map->len; i += 2) {
+ printf ("\t[%d] src %x dst %x\n ",
+ i / 2,
+ GPOINTER_TO_UINT (g_ptr_array_index (map, i)),
+ GPOINTER_TO_UINT (g_ptr_array_index (map, i + 1)));
+ }
+#endif
+
+ info->vcall_offset = vcall_offset;
+ info->map_count = map->len / 2;
+ for (i = 0; i < map->len; ++i)
+ info->map [i] = GPOINTER_TO_UINT (g_ptr_array_index (map, i));
+ g_ptr_array_free (map, TRUE);
+
+ /* Compute return value marshalling */
+ if (var_ret) {
+ /* Compute return value marshalling */
+ switch (cinfo->ret.storage) {
+ case ArgInIReg:
+ if (!gsharedvt_in || sig->ret->byref) {
+ info->ret_marshal = GSHAREDVT_RET_IREGS_1;
+ } else {
+ MonoType *ret = sig->ret;
+
+ // Unwrap enums
+ if (ret->type == MONO_TYPE_VALUETYPE)
+ ret = mini_type_get_underlying_type (ret);
+
+ switch (ret->type) {
+ case MONO_TYPE_I1:
+ info->ret_marshal = GSHAREDVT_RET_I1;
+ break;
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U1:
+ info->ret_marshal = GSHAREDVT_RET_U1;
+ break;
+ case MONO_TYPE_I2:
+ info->ret_marshal = GSHAREDVT_RET_I2;
+ break;
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_U2:
+ info->ret_marshal = GSHAREDVT_RET_U2;
+ break;
+ case MONO_TYPE_I4:
+ info->ret_marshal = GSHAREDVT_RET_I4;
+ break;
+ case MONO_TYPE_U4:
+ info->ret_marshal = GSHAREDVT_RET_U4;
+ break;
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_FNPTR:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8:
+ info->ret_marshal = GSHAREDVT_RET_I8;
+ break;
+
+ default:
+ g_error ("Gsharedvt can't handle dst type [%d]", (int)sig->ret->type);
+ }
+ }
+ break;
+ case ArgValuetypeInReg:
+ info->ret_marshal = GSHAREDVT_RET_IREGS_1 - 1 + cinfo->ret.nregs;
+ g_assert (cinfo->ret.nregs == 1); // ABI supports 2-register return but we do not implement this.
+ break;
+ case ArgInDoubleSSEReg:
+ case ArgInFloatSSEReg:
+ info->ret_marshal = GSHAREDVT_RET_R8;
+ break;
+ case ArgValuetypeAddrInIReg:
+ break;
+ default:
+ g_error ("Can't marshal return of storage [%d] %s", (int)cinfo->ret.storage, storage_name (cinfo->ret.storage));
+ }
+
+ if (gsharedvt_in && cinfo->ret.storage != ArgValuetypeAddrInIReg) {
+ /* Allocate stack space for the return value */
+ info->vret_slot = map_stack_slot (info->stack_usage / sizeof (gpointer));
+ info->stack_usage += mono_type_stack_size_internal (normal_sig->ret, NULL, FALSE) + sizeof (gpointer);
+ }
+ DEBUG_AMD64_GSHAREDVT_PRINT ("RET marshal is %s\n", ret_marshal_name [info->ret_marshal]);
+ }
+
+ info->stack_usage = ALIGN_TO (info->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
+
+ DEBUG_AMD64_GSHAREDVT_PRINT ("allocated an info at %p stack usage %d\n", info, info->stack_usage);
+ return info;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * mini-exceptions-native-unwinder.c: libcorkscrew-based native unwinder
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ * Rodrigo Kumpera <kumpera@gmail.com>
+ * Andi McClure <andi.mcclure@xamarin.com>
+ *
+ * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#ifndef MINI_AMD64_GSHAREDVT_H
+#define MINI_AMD64_GSHAREDVT_H
+
+typedef enum {
+ GSHAREDVT_ARG_NONE = 0,
+ GSHAREDVT_ARG_BYVAL_TO_BYREF,
+ GSHAREDVT_ARG_BYREF_TO_BYVAL,
+} GSharedVtArgMarshal;
+
+typedef enum {
+ GSHAREDVT_RET_NONE = 0,
+ GSHAREDVT_RET_I1, // 1 byte integer
+ GSHAREDVT_RET_U1, // 1 byte unsigned
+ GSHAREDVT_RET_I2, // 2 byte integer
+ GSHAREDVT_RET_U2, // 2 byte unsigned
+ GSHAREDVT_RET_I4, // 4 byte integer
+ GSHAREDVT_RET_U4, // 4 byte unsigned
+ GSHAREDVT_RET_I8, // 8 byte integer
+ GSHAREDVT_RET_IREGS_1, // Load in first return register
+ GSHAREDVT_RET_R8, // Double
+ GSHAREDVT_RET_NUM,
+} GSharedVtRetMarshal;
+
+static const char* ret_marshal_name[] = {
+ "GSHAREDVT_RET_NONE",
+ "GSHAREDVT_RET_I1",
+ "GSHAREDVT_RET_U1",
+ "GSHAREDVT_RET_I2",
+ "GSHAREDVT_RET_U2",
+ "GSHAREDVT_RET_I4",
+ "GSHAREDVT_RET_U4",
+ "GSHAREDVT_RET_I8",
+ "GSHAREDVT_RET_IREGS_1",
+ "GSHAREDVT_RET_R8",
+ "GSHAREDVT_RET_NUM",
+};
+
+#ifdef DEBUG_AMD64_GSHAREDVT
+#define DEBUG_AMD64_GSHAREDVT_PRINT printf
+#else
+#define DEBUG_AMD64_GSHAREDVT_PRINT(...)
+#endif
+
+#endif /* MINI_AMD64_GSHAREDVT_H */
\ No newline at end of file
* (C) 2003 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
#include <string.h>
amd64_patch (code, target);
}
-typedef enum {
- ArgInIReg,
- ArgInFloatSSEReg,
- ArgInDoubleSSEReg,
- ArgOnStack,
- ArgValuetypeInReg,
- ArgValuetypeAddrInIReg,
- /* gsharedvt argument passed by addr */
- ArgGSharedVtInReg,
- ArgGSharedVtOnStack,
- ArgNone /* only in pair_storage */
-} ArgStorage;
-
-typedef struct {
- gint16 offset;
- gint8 reg;
- ArgStorage storage : 8;
- gboolean is_gsharedvt_return_value : 1;
-
- /* Only if storage == ArgValuetypeInReg */
- ArgStorage pair_storage [2];
- gint8 pair_regs [2];
- /* The size of each pair (bytes) */
- int pair_size [2];
- int nregs;
- /* Only if storage == ArgOnStack */
- int arg_size; // Bytes, will always be rounded up/aligned to 8 byte boundary
-} ArgInfo;
-
-typedef struct {
- int nargs;
- guint32 stack_usage;
- guint32 reg_usage;
- guint32 freg_usage;
- gboolean need_stack_align;
- /* The index of the vret arg in the argument list */
- int vret_arg_index;
- ArgInfo ret;
- ArgInfo sig_cookie;
- ArgInfo args [1];
-} CallInfo;
-
#define DEBUG(a) if (cfg->verbose_level > 1) a
static void inline
mono_aot_register_jit_icall ("mono_amd64_throw_corlib_exception", mono_amd64_throw_corlib_exception);
mono_aot_register_jit_icall ("mono_amd64_resume_unwind", mono_amd64_resume_unwind);
mono_aot_register_jit_icall ("mono_amd64_get_original_ip", mono_amd64_get_original_ip);
-#if defined(ENABLE_GSHAREDVT)
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
mono_aot_register_jit_icall ("mono_amd64_start_gsharedvt_call", mono_amd64_start_gsharedvt_call);
#endif
return code;
}
-#define REAL_PRINT_REG(text,reg) \
-mono_assert (reg >= 0); \
-amd64_push_reg (code, AMD64_RAX); \
-amd64_push_reg (code, AMD64_RDX); \
-amd64_push_reg (code, AMD64_RCX); \
-amd64_push_reg (code, reg); \
-amd64_push_imm (code, reg); \
-amd64_push_imm (code, text " %d %p\n"); \
-amd64_mov_reg_imm (code, AMD64_RAX, printf); \
-amd64_call_reg (code, AMD64_RAX); \
-amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 3*4); \
-amd64_pop_reg (code, AMD64_RCX); \
-amd64_pop_reg (code, AMD64_RDX); \
-amd64_pop_reg (code, AMD64_RAX);
-
/* benchmark and set based on cpu */
#define LOOP_ALIGNMENT 8
#define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
}
}
-#if defined(ENABLE_GSHAREDVT) && defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
-
-#include "../../../mono-extensions/mono/mini/mini-amd64-gsharedvt.c"
-
-#endif /* !ENABLE_GSHAREDVT */
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+ return get_call_info (mp, sig);
+}
guint8 buffer [256];
} DynCallArgs;
+typedef enum {
+ ArgInIReg,
+ ArgInFloatSSEReg,
+ ArgInDoubleSSEReg,
+ ArgOnStack,
+ ArgValuetypeInReg,
+ ArgValuetypeAddrInIReg,
+ /* gsharedvt argument passed by addr */
+ ArgGSharedVtInReg,
+ ArgGSharedVtOnStack,
+ ArgNone /* only in pair_storage */
+} ArgStorage;
+
+typedef struct {
+ gint16 offset;
+ gint8 reg;
+ ArgStorage storage : 8;
+ gboolean is_gsharedvt_return_value : 1;
+
+ /* Only if storage == ArgValuetypeInReg */
+ ArgStorage pair_storage [2];
+ gint8 pair_regs [2];
+ /* The size of each pair (bytes) */
+ int pair_size [2];
+ int nregs;
+ /* Only if storage == ArgOnStack */
+ int arg_size; // Bytes, will always be rounded up/aligned to 8 byte boundary
+} ArgInfo;
+
+typedef struct {
+ int nargs;
+ guint32 stack_usage;
+ guint32 reg_usage;
+ guint32 freg_usage;
+ gboolean need_stack_align;
+ /* The index of the vret arg in the argument list */
+ int vret_arg_index;
+ ArgInfo ret;
+ ArgInfo sig_cookie;
+ ArgInfo args [1];
+} CallInfo;
+
+
#define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->gregs [AMD64_RAX] = (gsize)exc; } while (0)
#define MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG(ctx, sel) do { (ctx)->gregs [AMD64_RDX] = (gsize)(sel); } while (0)
#define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
#define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
#define MONO_ARCH_HAVE_CREATE_LLVM_NATIVE_THUNK 1
-#define MONO_ARCH_GSHAREDVT_SUPPORTED 1
#define MONO_ARCH_HAVE_OP_TAIL_CALL 1
#define MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET 1
#define MONO_ARCH_HAVE_DUMMY_INIT 1
#define MONO_ARCH_HAVE_TLS_GET_REG 1
#endif
+#if !defined (TARGET_WIN32)
+#define MONO_ARCH_GSHAREDVT_SUPPORTED 1
+#endif
+
+
#if defined(TARGET_APPLETVOS)
/* No signals */
#define MONO_ARCH_NEED_DIV_CHECK 1
#define MONO_ARCH_HAVE_UNWIND_TABLE 1
#endif
+CallInfo* mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);
+
#endif /* __MONO_MINI_AMD64_H__ */
--- /dev/null
+/*
+ * mini-arm-gsharedvt.c: gsharedvt support code for arm
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ *
+ * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/abi-details.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
+#include <mono/metadata/tabledefs.h>
+#include <mono/metadata/profiler-private.h>
+#include <mono/arch/arm/arm-codegen.h>
+#include <mono/arch/arm/arm-vfp-codegen.h>
+
+#include "mini.h"
+#include "mini-arm.h"
+
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+/*
+ * GSHAREDVT
+ */
+
+gboolean
+mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
+{
+ /*
+ if (sig->ret && is_variable_size (sig->ret))
+ return FALSE;
+ */
+ return TRUE;
+}
+
+static inline void
+add_to_map (GPtrArray *map, int src, int dst)
+{
+ g_ptr_array_add (map, GUINT_TO_POINTER (src));
+ g_ptr_array_add (map, GUINT_TO_POINTER (dst));
+}
+
+static inline int
+map_reg (int reg)
+{
+ return reg;
+}
+
+static inline int
+map_stack_slot (int slot)
+{
+ return slot + 4;
+}
+
+static int
+get_arg_slots (ArgInfo *ainfo, int **out_slots)
+{
+ int sreg = ainfo->reg;
+ int sslot = ainfo->offset / 4;
+ int *src = NULL;
+ int i, nsrc;
+
+ switch (ainfo->storage) {
+ case RegTypeGeneral:
+ nsrc = 1;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_reg (sreg);
+ break;
+ case RegTypeIRegPair:
+ nsrc = 2;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_reg (sreg);
+ src [1] = map_reg (sreg + 1);
+ break;
+ case RegTypeStructByVal:
+ nsrc = ainfo->struct_size / 4;
+ src = g_malloc (nsrc * sizeof (int));
+ g_assert (ainfo->size <= nsrc);
+ for (i = 0; i < ainfo->size; ++i)
+ src [i] = map_reg (sreg + i);
+ for (i = ainfo->size; i < nsrc; ++i)
+ src [i] = map_stack_slot (sslot + (i - ainfo->size));
+ break;
+ case RegTypeBase:
+ nsrc = ainfo->size / 4;
+ src = g_malloc (nsrc * sizeof (int));
+ for (i = 0; i < nsrc; ++i)
+ src [i] = map_stack_slot (sslot + i);
+ break;
+ case RegTypeBaseGen:
+ nsrc = 2;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_reg (ARMREG_R3);
+ src [1] = map_stack_slot (sslot);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ *out_slots = src;
+ return nsrc;
+}
+
+/*
+ * mono_arch_get_gsharedvt_call_info:
+ *
+ * See mini-x86.c for documentation.
+ */
+gpointer
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
+{
+ GSharedVtCallInfo *info;
+ CallInfo *caller_cinfo, *callee_cinfo;
+ MonoMethodSignature *caller_sig, *callee_sig;
+ int aindex, i;
+ gboolean var_ret = FALSE;
+ CallInfo *cinfo, *gcinfo;
+ MonoMethodSignature *sig, *gsig;
+ GPtrArray *map;
+
+ if (gsharedvt_in) {
+ caller_sig = normal_sig;
+ callee_sig = gsharedvt_sig;
+ caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+ callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+ } else {
+ callee_sig = normal_sig;
+ callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+ caller_sig = gsharedvt_sig;
+ caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+ }
+
+ /*
+ * If GSHAREDVT_IN is true, this means we are transitioning from normal to gsharedvt code. The caller uses the
+ * normal call signature, while the callee uses the gsharedvt signature.
+ * If GSHAREDVT_IN is false, its the other way around.
+ */
+
+ /* sig/cinfo describes the normal call, while gsig/gcinfo describes the gsharedvt call */
+ if (gsharedvt_in) {
+ sig = caller_sig;
+ gsig = callee_sig;
+ cinfo = caller_cinfo;
+ gcinfo = callee_cinfo;
+ } else {
+ sig = callee_sig;
+ gsig = caller_sig;
+ cinfo = callee_cinfo;
+ gcinfo = caller_cinfo;
+ }
+
+ if (gcinfo->ret.storage == RegTypeStructByAddr && gsig->ret && mini_is_gsharedvt_type (gsig->ret)) {
+ /*
+ * The return type is gsharedvt
+ */
+ var_ret = TRUE;
+ }
+
+ /*
+ * The stack looks like this:
+ * <arguments>
+ * <ret addr>
+ * <saved ebp>
+ * <call area>
+ * We have to map the stack slots in <arguments> to the stack slots in <call area>.
+ * The argument registers are mapped to slot 0..3, stack slot 0 is mapped to slot 4, etc.
+ */
+ map = g_ptr_array_new ();
+
+ if (cinfo->ret.storage == RegTypeStructByAddr) {
+ /*
+ * Map ret arg.
+ * This handles the case when the method returns a normal vtype, and when it returns a type arg, and its instantiated
+ * with a vtype.
+ */
+ g_assert (caller_cinfo->ret.storage == RegTypeStructByAddr);
+ g_assert (callee_cinfo->ret.storage == RegTypeStructByAddr);
+ add_to_map (map, map_reg (caller_cinfo->ret.reg), map_reg (callee_cinfo->ret.reg));
+ }
+
+ for (aindex = 0; aindex < cinfo->nargs; ++aindex) {
+ ArgInfo *ainfo = &caller_cinfo->args [aindex];
+ ArgInfo *ainfo2 = &callee_cinfo->args [aindex];
+ int *src = NULL, *dst = NULL;
+ int nsrc, ndst, nslots, src_slot, arg_marshal;
+
+ /*
+ * The src descriptor looks like this:
+ * - 4 bits src slot
+ * - 12 bits number of slots
+ * - 8 bits marshal type (GSHAREDVT_ARG_...)
+ */
+
+ arg_marshal = GSHAREDVT_ARG_NONE;
+
+ if (ainfo->storage == RegTypeGSharedVtInReg || ainfo->storage == RegTypeGSharedVtOnStack) {
+ /* Pass the value whose address is received in a reg by value */
+ g_assert (ainfo2->storage != RegTypeGSharedVtInReg);
+ ndst = get_arg_slots (ainfo2, &dst);
+ nsrc = 1;
+ src = g_new0 (int, 1);
+ if (ainfo->storage == RegTypeGSharedVtInReg)
+ src_slot = map_reg (ainfo->reg);
+ else
+ src_slot = map_stack_slot (ainfo->offset / 4);
+ g_assert (ndst < 256);
+ g_assert (src_slot < 16);
+ src [0] = (ndst << 4) | src_slot;
+
+ if (ainfo2->storage == RegTypeGeneral && ainfo2->size != 0 && ainfo2->size != 4) {
+ /* Have to load less than 4 bytes */
+ // FIXME: Signed types
+ switch (ainfo2->size) {
+ case 1:
+ arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL_U1;
+ break;
+ case 2:
+ arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL_U2;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ } else {
+ arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL;
+ }
+ } else {
+ nsrc = get_arg_slots (ainfo, &src);
+ }
+ if (ainfo2->storage == RegTypeGSharedVtInReg) {
+ /* Pass the address of the first src slot in a reg */
+ arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
+ ndst = 1;
+ dst = g_new0 (int, 1);
+ dst [0] = map_reg (ainfo2->reg);
+ } else if (ainfo2->storage == RegTypeGSharedVtOnStack) {
+ /* Pass the address of the first src slot in a stack slot */
+ arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
+ ndst = 1;
+ dst = g_new0 (int, 1);
+ dst [0] = map_stack_slot (ainfo2->offset / 4);
+ } else {
+ ndst = get_arg_slots (ainfo2, &dst);
+ }
+ if (nsrc)
+ src [0] |= (arg_marshal << 16);
+ nslots = MIN (nsrc, ndst);
+
+ for (i = 0; i < nslots; ++i)
+ add_to_map (map, src [i], dst [i]);
+
+ g_free (src);
+ g_free (dst);
+ }
+
+ info = mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo) + (map->len * sizeof (int)));
+ info->addr = addr;
+ info->stack_usage = callee_cinfo->stack_usage;
+ info->ret_marshal = GSHAREDVT_RET_NONE;
+ info->gsharedvt_in = gsharedvt_in ? 1 : 0;
+ info->vret_slot = -1;
+ info->calli = calli;
+ if (var_ret) {
+ g_assert (gcinfo->ret.storage == RegTypeStructByAddr);
+ info->vret_arg_reg = gcinfo->ret.reg;
+ } else {
+ info->vret_arg_reg = -1;
+ }
+ info->vcall_offset = vcall_offset;
+ info->map_count = map->len / 2;
+ for (i = 0; i < map->len; ++i)
+ info->map [i] = GPOINTER_TO_UINT (g_ptr_array_index (map, i));
+ g_ptr_array_free (map, TRUE);
+
+ /* Compute return value marshalling */
+ if (var_ret) {
+ switch (cinfo->ret.storage) {
+ case RegTypeGeneral:
+ if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I1)
+ info->ret_marshal = GSHAREDVT_RET_I1;
+ else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U1 || sig->ret->type == MONO_TYPE_BOOLEAN))
+ info->ret_marshal = GSHAREDVT_RET_U1;
+ else if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I2)
+ info->ret_marshal = GSHAREDVT_RET_I2;
+ else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U2 || sig->ret->type == MONO_TYPE_CHAR))
+ info->ret_marshal = GSHAREDVT_RET_U2;
+ else
+ info->ret_marshal = GSHAREDVT_RET_IREG;
+ break;
+ case RegTypeIRegPair:
+ info->ret_marshal = GSHAREDVT_RET_IREGS;
+ break;
+ case RegTypeFP:
+ // FIXME: VFP
+ if (cinfo->ret.size == 4)
+ info->ret_marshal = GSHAREDVT_RET_IREG;
+ else
+ info->ret_marshal = GSHAREDVT_RET_IREGS;
+ break;
+ case RegTypeStructByAddr:
+ info->ret_marshal = GSHAREDVT_RET_NONE;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ if (gsharedvt_in && var_ret && caller_cinfo->ret.storage != RegTypeStructByAddr) {
+ /* Allocate stack space for the return value */
+ info->vret_slot = map_stack_slot (info->stack_usage / sizeof (gpointer));
+ info->stack_usage += mono_type_stack_size_internal (normal_sig->ret, NULL, FALSE) + sizeof (gpointer);
+ }
+
+ info->stack_usage = ALIGN_TO (info->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
+
+ g_free (caller_cinfo);
+ g_free (callee_cinfo);
+
+ return info;
+}
+
+#endif
\ No newline at end of file
* mini-arm-tls.S: tls getters and setters for arm platforms
*
* Copyright 2015 Xamarin, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* (C) 2003 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
#include <string.h>
mono_aot_register_jit_icall ("mono_arm_throw_exception", mono_arm_throw_exception);
mono_aot_register_jit_icall ("mono_arm_throw_exception_by_token", mono_arm_throw_exception_by_token);
mono_aot_register_jit_icall ("mono_arm_resume_unwind", mono_arm_resume_unwind);
-#if defined(ENABLE_GSHAREDVT)
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
mono_aot_register_jit_icall ("mono_arm_start_gsharedvt_call", mono_arm_start_gsharedvt_call);
#endif
mono_aot_register_jit_icall ("mono_arm_unaligned_stack", mono_arm_unaligned_stack);
#endif
}
-typedef enum {
- RegTypeNone,
- /* Passed/returned in an ireg */
- RegTypeGeneral,
- /* Passed/returned in a pair of iregs */
- RegTypeIRegPair,
- /* Passed on the stack */
- RegTypeBase,
- /* First word in r3, second word on the stack */
- RegTypeBaseGen,
- /* FP value passed in either an ireg or a vfp reg */
- RegTypeFP,
- RegTypeStructByVal,
- RegTypeStructByAddr,
- /* gsharedvt argument passed by addr in greg */
- RegTypeGSharedVtInReg,
- /* gsharedvt argument passed by addr on stack */
- RegTypeGSharedVtOnStack,
- RegTypeHFA
-} ArgStorage;
-
-typedef struct {
- gint32 offset;
- guint16 vtsize; /* in param area */
- /* RegTypeHFA */
- int esize;
- /* RegTypeHFA */
- int nregs;
- guint8 reg;
- ArgStorage storage;
- gint32 struct_size;
- guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
-} ArgInfo;
-
-typedef struct {
- int nargs;
- guint32 stack_usage;
- /* The index of the vret arg in the argument list for RegTypeStructByAddr */
- int vret_arg_index;
- ArgInfo ret;
- ArgInfo sig_cookie;
- ArgInfo args [1];
-} CallInfo;
-
#define DEBUG(a)
static void inline
} else {
int creg;
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
} else {
int creg;
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
/* This should work for soft-float as well */
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
mono_call_inst_add_outarg_reg (cfg, call, creg, ARMREG_R3, FALSE);
code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_LR);
#else
ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
- ARM_B (code, 2);
+ ARM_B (code, 1);
*(gpointer*)code = &single_step_tramp;
code += 4;
*(gpointer*)code = breakpoint_tramp;
patch_info->ip.i = code - cfg->native_code;
ARM_BL (code, 0);
cfg->thunk_area += THUNK_SIZE;
- *(guint32*)(gpointer)code = exc_class->type_token;
+ *(guint32*)(gpointer)code = exc_class->type_token - MONO_TOKEN_TYPE_DEF;
code += 4;
#endif
break;
}
}
-#if defined(ENABLE_GSHAREDVT)
-
-#include "../../../mono-extensions/mono/mini/mini-arm-gsharedvt.c"
-
-#endif /* !MONOTOUCH */
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+ return get_call_info (mp, sig);
+}
/*
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_MINI_ARM_H__
int map [MONO_ZERO_LEN_ARRAY];
} GSharedVtCallInfo;
+
+typedef enum {
+ RegTypeNone,
+ /* Passed/returned in an ireg */
+ RegTypeGeneral,
+ /* Passed/returned in a pair of iregs */
+ RegTypeIRegPair,
+ /* Passed on the stack */
+ RegTypeBase,
+ /* First word in r3, second word on the stack */
+ RegTypeBaseGen,
+ /* FP value passed in either an ireg or a vfp reg */
+ RegTypeFP,
+ RegTypeStructByVal,
+ RegTypeStructByAddr,
+ /* gsharedvt argument passed by addr in greg */
+ RegTypeGSharedVtInReg,
+ /* gsharedvt argument passed by addr on stack */
+ RegTypeGSharedVtOnStack,
+ RegTypeHFA
+} ArgStorage;
+
+typedef struct {
+ gint32 offset;
+ guint16 vtsize; /* in param area */
+ /* RegTypeHFA */
+ int esize;
+ /* RegTypeHFA */
+ int nregs;
+ guint8 reg;
+ ArgStorage storage;
+ gint32 struct_size;
+ guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
+} ArgInfo;
+
+typedef struct {
+ int nargs;
+ guint32 stack_usage;
+ /* The index of the vret arg in the argument list for RegTypeStructByAddr */
+ int vret_arg_index;
+ ArgInfo ret;
+ ArgInfo sig_cookie;
+ ArgInfo args [1];
+} CallInfo;
+
/* Structure used by the sequence points in AOTed code */
typedef struct {
gpointer ss_trigger_page;
void
mono_arm_unaligned_stack (MonoMethod *method);
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);
+
#endif /* __MONO_MINI_ARM_H__ */
--- /dev/null
+/*
+ * mini-arm64-gsharedvt.c: gsharedvt support code for arm64
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ *
+ * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include "mini.h"
+#include "mini-arm64.h"
+#include "mini-arm64-gsharedvt.h"
+
+/*
+ * GSHAREDVT
+ */
+#ifdef MONO_ARCH_GSHARED_SUPPORTED
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+void
+mono_arm_gsharedvt_init (void)
+{
+ mono_aot_register_jit_icall ("mono_arm_start_gsharedvt_call", mono_arm_start_gsharedvt_call);
+}
+
+gboolean
+mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
+{
+ /*
+ if (sig->ret && is_variable_size (sig->ret))
+ return FALSE;
+ */
+ return TRUE;
+}
+
+static inline void
+add_to_map (GPtrArray *map, int src, int dst)
+{
+ g_ptr_array_add (map, GUINT_TO_POINTER (src));
+ g_ptr_array_add (map, GUINT_TO_POINTER (dst));
+}
+
+/*
+ * Slot mapping:
+ * 0..8 - r0..r8
+ * 9..16 - d0..d7
+ * 17.. - stack slots
+ */
+
+static inline int
+map_reg (int reg)
+{
+ return reg;
+}
+
+static inline int
+map_freg (int reg)
+{
+ return reg + NUM_GSHAREDVT_ARG_GREGS;
+}
+
+static inline int
+map_stack_slot (int slot)
+{
+ return slot + NUM_GSHAREDVT_ARG_GREGS + NUM_GSHAREDVT_ARG_FREGS;
+}
+
+static int
+get_arg_slots (ArgInfo *ainfo, int **out_slots)
+{
+ int sreg = ainfo->reg;
+ int sslot = ainfo->offset / 8;
+ int *src = NULL;
+ int i, nsrc;
+
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ case ArgVtypeByRef:
+ nsrc = 1;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_reg (sreg);
+ break;
+ case ArgVtypeByRefOnStack:
+ nsrc = 1;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_stack_slot (sslot);
+ break;
+ case ArgInFReg:
+ case ArgInFRegR4:
+ nsrc = 1;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_freg (sreg);
+ break;
+ case ArgHFA:
+ nsrc = ainfo->nregs;
+ src = g_malloc (nsrc * sizeof (int));
+ for (i = 0; i < ainfo->nregs; ++i)
+ src [i] = map_freg (sreg + i);
+ break;
+ case ArgVtypeInIRegs:
+ nsrc = ainfo->nregs;
+ src = g_malloc (nsrc * sizeof (int));
+ for (i = 0; i < ainfo->nregs; ++i)
+ src [i] = map_reg (sreg + i);
+ break;
+ case ArgOnStack:
+ nsrc = 1;
+ src = g_malloc (nsrc * sizeof (int));
+ src [0] = map_stack_slot (sslot);
+ break;
+ case ArgVtypeOnStack:
+ nsrc = ainfo->size / 8;
+ src = g_malloc (nsrc * sizeof (int));
+ for (i = 0; i < nsrc; ++i)
+ src [i] = map_stack_slot (sslot + i);
+ break;
+ default:
+ NOT_IMPLEMENTED;
+ break;
+ }
+
+ *out_slots = src;
+ return nsrc;
+}
+
+/*
+ * mono_arch_get_gsharedvt_call_info:
+ *
+ * See mini-x86.c for documentation.
+ */
+gpointer
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
+{
+ GSharedVtCallInfo *info;
+ CallInfo *caller_cinfo, *callee_cinfo;
+ MonoMethodSignature *caller_sig, *callee_sig;
+ int aindex, i;
+ gboolean var_ret = FALSE;
+ CallInfo *cinfo, *gcinfo;
+ MonoMethodSignature *sig, *gsig;
+ GPtrArray *map;
+
+ if (gsharedvt_in) {
+ caller_sig = normal_sig;
+ callee_sig = gsharedvt_sig;
+ caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+ callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+ } else {
+ callee_sig = normal_sig;
+ caller_sig = gsharedvt_sig;
+ callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+ caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+ }
+
+ /*
+ * If GSHAREDVT_IN is true, this means we are transitioning from normal to gsharedvt code. The caller uses the
+ * normal call signature, while the callee uses the gsharedvt signature.
+ * If GSHAREDVT_IN is false, its the other way around.
+ */
+
+ /* sig/cinfo describes the normal call, while gsig/gcinfo describes the gsharedvt call */
+ if (gsharedvt_in) {
+ sig = caller_sig;
+ gsig = callee_sig;
+ cinfo = caller_cinfo;
+ gcinfo = callee_cinfo;
+ } else {
+ sig = callee_sig;
+ gsig = caller_sig;
+ cinfo = callee_cinfo;
+ gcinfo = caller_cinfo;
+ }
+
+ if (gcinfo->ret.gsharedvt) {
+ /*
+ * The return type is gsharedvt
+ */
+ var_ret = TRUE;
+ }
+
+ /*
+ * The stack looks like this:
+ * <arguments>
+ * <trampoline frame>
+ * <call area>
+ * We have to map the stack slots in <arguments> to the stack slots in <call area>.
+ */
+ map = g_ptr_array_new ();
+
+ for (aindex = 0; aindex < cinfo->nargs; ++aindex) {
+ ArgInfo *ainfo = &caller_cinfo->args [aindex];
+ ArgInfo *ainfo2 = &callee_cinfo->args [aindex];
+ int *src = NULL, *dst = NULL;
+ int nsrc, ndst, nslots, src_slot, arg_marshal;
+
+ /*
+ * The src descriptor looks like this:
+ * - 6 bits src slot
+ * - 12 bits number of slots
+ * - 4 bits marshal type (GSHAREDVT_ARG_...)
+ * - 4 bits size/sign descriptor (GSHAREDVT_ARG_SIZE)
+ * - 4 bits offset inside stack slots
+ */
+ arg_marshal = GSHAREDVT_ARG_NONE;
+
+ if (ainfo->gsharedvt) {
+ /* Pass the value whose address is received in a reg by value */
+ g_assert (!ainfo2->gsharedvt);
+ ndst = get_arg_slots (ainfo2, &dst);
+ nsrc = 1;
+ src = g_new0 (int, 1);
+ if (ainfo->storage == ArgVtypeByRef)
+ src_slot = map_reg (ainfo->reg);
+ else
+ src_slot = map_stack_slot (ainfo->offset / 8);
+ g_assert (ndst < 256);
+ g_assert (src_slot < 64);
+ src [0] = (ndst << 6) | src_slot;
+ if (ainfo2->storage == ArgHFA && ainfo2->esize == 4)
+ arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL_HFAR4;
+ else if (ainfo2->storage == ArgVtypeByRef || ainfo2->storage == ArgVtypeByRefOnStack)
+ arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYREF;
+ else
+ arg_marshal = GSHAREDVT_ARG_BYREF_TO_BYVAL;
+ } else {
+ nsrc = get_arg_slots (ainfo, &src);
+ }
+ if (ainfo2->storage == ArgVtypeByRef && ainfo2->gsharedvt) {
+ /* Pass the address of the first src slot in a reg */
+ if (ainfo->storage != ArgVtypeByRef) {
+ if (ainfo->storage == ArgHFA && ainfo->esize == 4) {
+ arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF_HFAR4;
+ g_assert (src [0] < 64);
+ g_assert (nsrc < 256);
+ src [0] |= (nsrc << 6);
+ } else {
+ arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
+ }
+ }
+ ndst = 1;
+ dst = g_new0 (int, 1);
+ dst [0] = map_reg (ainfo2->reg);
+ } else if (ainfo2->storage == ArgVtypeByRefOnStack && ainfo2->gsharedvt) {
+ /* Pass the address of the first src slot in a stack slot */
+ if (ainfo->storage != ArgVtypeByRef)
+ arg_marshal = GSHAREDVT_ARG_BYVAL_TO_BYREF;
+ ndst = 1;
+ dst = g_new0 (int, 1);
+ dst [0] = map_stack_slot (ainfo2->offset / 8);
+ } else {
+ ndst = get_arg_slots (ainfo2, &dst);
+ }
+ if (nsrc)
+ src [0] |= (arg_marshal << 18);
+ if (ainfo->storage == ArgOnStack && ainfo->slot_size != 8) {
+ GSharedVtArgSize arg_size = GSHAREDVT_ARG_SIZE_NONE;
+
+ /*
+ * On IOS, stack arguments smaller than 8 bytes can
+ * share a stack slot. Encode this information into
+ * the descriptor.
+ */
+ switch (ainfo->slot_size) {
+ case 1:
+ arg_size = ainfo->sign ? GSHAREDVT_ARG_SIZE_I1 : GSHAREDVT_ARG_SIZE_U1;
+ break;
+ case 2:
+ arg_size = ainfo->sign ? GSHAREDVT_ARG_SIZE_I2 : GSHAREDVT_ARG_SIZE_U2;
+ break;
+ case 4:
+ arg_size = ainfo->sign ? GSHAREDVT_ARG_SIZE_I4 : GSHAREDVT_ARG_SIZE_U4;
+ break;
+ default:
+ NOT_IMPLEMENTED;
+ break;
+ }
+ /* Encode the size/sign */
+ src [0] |= (arg_size << 22);
+ /* Encode the offset inside the stack slot */
+ src [0] |= ((ainfo->offset % 8) << 26);
+ if (ainfo2->storage == ArgOnStack)
+ dst [0] |= ((ainfo2->offset % 8) << 26);
+ } else if (ainfo2->storage == ArgOnStack && ainfo2->slot_size != 8) {
+ /* The caller passes in an address, need to store it into a stack slot */
+
+ GSharedVtArgSize arg_size = GSHAREDVT_ARG_SIZE_NONE;
+ switch (ainfo2->slot_size) {
+ case 1:
+ arg_size = ainfo2->sign ? GSHAREDVT_ARG_SIZE_I1 : GSHAREDVT_ARG_SIZE_U1;
+ break;
+ case 2:
+ arg_size = ainfo2->sign ? GSHAREDVT_ARG_SIZE_I2 : GSHAREDVT_ARG_SIZE_U2;
+ break;
+ case 4:
+ arg_size = ainfo2->sign ? GSHAREDVT_ARG_SIZE_I4 : GSHAREDVT_ARG_SIZE_U4;
+ break;
+ default:
+ NOT_IMPLEMENTED;
+ break;
+ }
+ /* Encode the size/sign */
+ src [0] |= (arg_size << 22);
+ /* Encode the offset inside the stack slot */
+ dst [0] |= ((ainfo2->offset % 8) << 26);
+ }
+ nslots = MIN (nsrc, ndst);
+
+ for (i = 0; i < nslots; ++i)
+ add_to_map (map, src [i], dst [i]);
+
+ g_free (src);
+ g_free (dst);
+ }
+
+ if (cinfo->ret.storage == ArgVtypeByRef) {
+ /* Both the caller and the callee pass the vtype ret address in r8 */
+ g_assert (cinfo->ret.storage == gcinfo->ret.storage);
+ add_to_map (map, map_reg (ARMREG_R8), map_reg (ARMREG_R8));
+ }
+
+ info = mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo) + (map->len * sizeof (int)));
+ info->addr = addr;
+ info->stack_usage = callee_cinfo->stack_usage;
+ info->ret_marshal = GSHAREDVT_RET_NONE;
+ info->gsharedvt_in = gsharedvt_in ? 1 : 0;
+ info->vret_slot = -1;
+ info->calli = calli;
+
+ if (var_ret) {
+ g_assert (gcinfo->ret.gsharedvt);
+ info->vret_arg_reg = map_reg (ARMREG_R8);
+ } else {
+ info->vret_arg_reg = -1;
+ }
+
+ info->vcall_offset = vcall_offset;
+ info->map_count = map->len / 2;
+ for (i = 0; i < map->len; ++i)
+ info->map [i] = GPOINTER_TO_UINT (g_ptr_array_index (map, i));
+ g_ptr_array_free (map, TRUE);
+
+ /* Compute return value marshalling */
+ if (var_ret) {
+ switch (cinfo->ret.storage) {
+ case ArgInIReg:
+ if (!gsharedvt_in || sig->ret->byref) {
+ info->ret_marshal = GSHAREDVT_RET_I8;
+ } else {
+ switch (sig->ret->type) {
+ case MONO_TYPE_I1:
+ info->ret_marshal = GSHAREDVT_RET_I1;
+ break;
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ info->ret_marshal = GSHAREDVT_RET_U1;
+ break;
+ case MONO_TYPE_I2:
+ info->ret_marshal = GSHAREDVT_RET_I2;
+ break;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ info->ret_marshal = GSHAREDVT_RET_U2;
+ break;
+ case MONO_TYPE_I4:
+ info->ret_marshal = GSHAREDVT_RET_I4;
+ break;
+ case MONO_TYPE_U4:
+ info->ret_marshal = GSHAREDVT_RET_U4;
+ break;
+ default:
+ info->ret_marshal = GSHAREDVT_RET_I8;
+ break;
+ }
+ }
+ break;
+ case ArgInFReg:
+ info->ret_marshal = GSHAREDVT_RET_R8;
+ break;
+ case ArgInFRegR4:
+ info->ret_marshal = GSHAREDVT_RET_R4;
+ break;
+ case ArgVtypeInIRegs:
+ info->ret_marshal = GSHAREDVT_RET_IREGS_1 - 1 + cinfo->ret.nregs;
+ break;
+ case ArgHFA:
+ if (cinfo->ret.esize == 4)
+ info->ret_marshal = GSHAREDVT_RET_HFAR4_1 - 1 + cinfo->ret.nregs;
+ else
+ info->ret_marshal = GSHAREDVT_RET_HFAR8_1 - 1 + cinfo->ret.nregs;
+ break;
+ case ArgVtypeByRef:
+ /* No conversion needed */
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ if (gsharedvt_in && var_ret && cinfo->ret.storage != ArgVtypeByRef) {
+ /* Allocate stack space for the return value */
+ info->vret_slot = map_stack_slot (info->stack_usage / sizeof (gpointer));
+ info->stack_usage += mono_type_stack_size_internal (normal_sig->ret, NULL, FALSE) + sizeof (gpointer);
+ }
+
+ info->stack_usage = ALIGN_TO (info->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
+
+ return info;
+}
+
+#else
+
+void
+mono_arm_gsharedvt_init (void)
+{
+}
+
+#endif /* MONO_ARCH_GSHARED_SUPPORTED */
\ No newline at end of file
--- /dev/null
+#ifndef __MINI_ARM64_GSHAREDVT_H__
+#define __MINI_ARM64_GSHAREDVT_H__
+
+/* Argument marshallings for calls between gsharedvt and normal code */
+typedef enum {
+ GSHAREDVT_ARG_NONE = 0,
+ GSHAREDVT_ARG_BYVAL_TO_BYREF = 1,
+ GSHAREDVT_ARG_BYVAL_TO_BYREF_HFAR4 = 2,
+ GSHAREDVT_ARG_BYREF_TO_BYVAL = 3,
+ GSHAREDVT_ARG_BYREF_TO_BYVAL_HFAR4 = 4,
+ GSHAREDVT_ARG_BYREF_TO_BYREF = 5
+} GSharedVtArgMarshal;
+
+/* For arguments passed on the stack on ios */
+typedef enum {
+ GSHAREDVT_ARG_SIZE_NONE = 0,
+ GSHAREDVT_ARG_SIZE_I1 = 1,
+ GSHAREDVT_ARG_SIZE_U1 = 2,
+ GSHAREDVT_ARG_SIZE_I2 = 3,
+ GSHAREDVT_ARG_SIZE_U2 = 4,
+ GSHAREDVT_ARG_SIZE_I4 = 5,
+ GSHAREDVT_ARG_SIZE_U4 = 6,
+} GSharedVtArgSize;
+
+/* Return value marshalling for calls between gsharedvt and normal code */
+typedef enum {
+ GSHAREDVT_RET_NONE = 0,
+ GSHAREDVT_RET_I8 = 1,
+ GSHAREDVT_RET_I1 = 2,
+ GSHAREDVT_RET_U1 = 3,
+ GSHAREDVT_RET_I2 = 4,
+ GSHAREDVT_RET_U2 = 5,
+ GSHAREDVT_RET_I4 = 6,
+ GSHAREDVT_RET_U4 = 7,
+ GSHAREDVT_RET_R8 = 8,
+ GSHAREDVT_RET_R4 = 9,
+ GSHAREDVT_RET_IREGS_1 = 10,
+ GSHAREDVT_RET_IREGS_2 = 11,
+ GSHAREDVT_RET_IREGS_3 = 12,
+ GSHAREDVT_RET_IREGS_4 = 13,
+ GSHAREDVT_RET_IREGS_5 = 14,
+ GSHAREDVT_RET_IREGS_6 = 15,
+ GSHAREDVT_RET_IREGS_7 = 16,
+ GSHAREDVT_RET_IREGS_8 = 17,
+ GSHAREDVT_RET_HFAR8_1 = 18,
+ GSHAREDVT_RET_HFAR8_2 = 19,
+ GSHAREDVT_RET_HFAR8_3 = 20,
+ GSHAREDVT_RET_HFAR8_4 = 21,
+ GSHAREDVT_RET_HFAR4_1 = 22,
+ GSHAREDVT_RET_HFAR4_2 = 23,
+ GSHAREDVT_RET_HFAR4_3 = 24,
+ GSHAREDVT_RET_HFAR4_4 = 25,
+ GSHAREDVT_RET_NUM = 26
+} GSharedVtRetMarshal;
+
+typedef struct {
+ /* Method address to call */
+ gpointer addr;
+ /* The trampoline reads this, so keep the size explicit */
+ int ret_marshal;
+ /* If ret_marshal != NONE, this is the reg of the vret arg, else -1 */
+ /* Equivalent of vret_arg_slot in x86 implementation. */
+ int vret_arg_reg;
+ /* The stack slot where the return value will be stored */
+ int vret_slot;
+ int stack_usage, map_count;
+ /* If not -1, then make a virtual call using this vtable offset */
+ int vcall_offset;
+ /* If 1, make an indirect call to the address in the rgctx reg */
+ int calli;
+ /* Whenever this is a in or an out call */
+ int gsharedvt_in;
+ /* Maps stack slots/registers in the caller to the stack slots/registers in the callee */
+ int map [MONO_ZERO_LEN_ARRAY];
+} GSharedVtCallInfo;
+
+/* Number of argument registers (r0..r8) */
+#define NUM_GSHAREDVT_ARG_GREGS 9
+#define NUM_GSHAREDVT_ARG_FREGS 8
+
+gpointer
+mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg);
+
+#endif /* __MINI_ARM64_GSHAREDVT_H__ */
-#include "../../../mono-extensions/mono/mini/mini-arm64.c"
+/*
+ * mini-arm64.c: ARM64 backend for the Mono code generator
+ *
+ * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
+ *
+ * Based on mini-arm.c:
+ *
+ * Authors:
+ * Paolo Molaro (lupus@ximian.com)
+ * Dietmar Maurer (dietmar@ximian.com)
+ *
+ * (C) 2003 Ximian, Inc.
+ * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include "mini.h"
+#include "cpu-arm64.h"
+#include "ir-emit.h"
+
+#include <mono/arch/arm64/arm64-codegen.h>
+#include <mono/utils/mono-mmap.h>
+#include <mono/utils/mono-memory-model.h>
+#include <mono/metadata/abi-details.h>
+
+/*
+ * Documentation:
+ *
+ * - ARM(R) Architecture Reference Manual, ARMv8, for ARMv8-A architecture profile (DDI0487A_a_armv8_arm.pdf)
+ * - Procedure Call Standard for the ARM 64-bit Architecture (AArch64) (IHI0055B_aapcs64.pdf)
+ * - ELF for the ARM 64-bit Architecture (IHI0056B_aaelf64.pdf)
+ *
+ * Register usage:
+ * - ip0/ip1/lr are used as temporary registers
+ * - r27 is used as the rgctx/imt register
+ * - r28 is used to access arguments passed on the stack
+ * - d15/d16 are used as fp temporary registers
+ */
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+#define FP_TEMP_REG ARMREG_D16
+#define FP_TEMP_REG2 ARMREG_D17
+
+#define THUNK_SIZE (4 * 4)
+
+/* The single step trampoline */
+static gpointer ss_trampoline;
+
+/* The breakpoint trampoline */
+static gpointer bp_trampoline;
+
+static gboolean ios_abi;
+
+static __attribute__((warn_unused_result)) guint8* emit_load_regset (guint8 *code, guint64 regs, int basereg, int offset);
+
+const char*
+mono_arch_regname (int reg)
+{
+ static const char * rnames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
+ "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
+ "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "fp",
+ "lr", "sp"
+ };
+ if (reg >= 0 && reg < 32)
+ return rnames [reg];
+ return "unknown";
+}
+
+const char*
+mono_arch_fregname (int reg)
+{
+ static const char * rnames[] = {
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
+ "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+ "d30", "d31"
+ };
+ if (reg >= 0 && reg < 32)
+ return rnames [reg];
+ return "unknown fp";
+}
+
+int
+mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
+{
+ NOT_IMPLEMENTED;
+ return 0;
+}
+
+#define MAX_ARCH_DELEGATE_PARAMS 7
+
+static gpointer
+get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
+{
+ guint8 *code, *start;
+
+ if (has_target) {
+ start = code = mono_global_codeman_reserve (12);
+
+ /* Replace the this argument with the target */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ arm_ldrx (code, ARMREG_R0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, target));
+ arm_brx (code, ARMREG_IP0);
+
+ g_assert ((code - start) <= 12);
+
+ mono_arch_flush_icache (start, 12);
+ } else {
+ int size, i;
+
+ size = 8 + param_count * 4;
+ start = code = mono_global_codeman_reserve (size);
+
+ arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+ /* slide down the arguments */
+ for (i = 0; i < param_count; ++i)
+ arm_movx (code, i, i + 1);
+ arm_brx (code, ARMREG_IP0);
+
+ g_assert ((code - start) <= size);
+
+ mono_arch_flush_icache (start, size);
+ }
+
+ if (code_size)
+ *code_size = code - start;
+
+ return start;
+}
+
+/*
+ * mono_arch_get_delegate_invoke_impls:
+ *
+ * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
+ * trampolines.
+ */
+GSList*
+mono_arch_get_delegate_invoke_impls (void)
+{
+ GSList *res = NULL;
+ guint8 *code;
+ guint32 code_len;
+ int i;
+ char *tramp_name;
+
+ code = get_delegate_invoke_impl (TRUE, 0, &code_len);
+ res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
+
+ for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
+ code = get_delegate_invoke_impl (FALSE, i, &code_len);
+ tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
+ res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
+ g_free (tramp_name);
+ }
+
+ return res;
+}
+
+gpointer
+mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
+{
+ guint8 *code, *start;
+
+ /*
+ * vtypes are returned in registers, or using the dedicated r8 register, so
+ * they can be supported by delegate invokes.
+ */
+
+ if (has_target) {
+ static guint8* cached = NULL;
+
+ if (cached)
+ return cached;
+
+ if (mono_aot_only)
+ start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
+ else
+ start = get_delegate_invoke_impl (TRUE, 0, NULL);
+ mono_memory_barrier ();
+ cached = start;
+ return cached;
+ } else {
+ static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
+ int i;
+
+ if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
+ return NULL;
+ for (i = 0; i < sig->param_count; ++i)
+ if (!mono_is_regsize_var (sig->params [i]))
+ return NULL;
+
+ code = cache [sig->param_count];
+ if (code)
+ return code;
+
+ if (mono_aot_only) {
+ char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
+ start = mono_aot_get_trampoline (name);
+ g_free (name);
+ } else {
+ start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
+ }
+ mono_memory_barrier ();
+ cache [sig->param_count] = start;
+ return start;
+ }
+
+ return NULL;
+}
+
+gpointer
+mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
+{
+ return NULL;
+}
+
+gpointer
+mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
+{
+ return (gpointer)regs [ARMREG_R0];
+}
+
+void
+mono_arch_cpu_init (void)
+{
+}
+
+void
+mono_arch_init (void)
+{
+ mono_aot_register_jit_icall ("mono_arm_throw_exception", mono_arm_throw_exception);
+ mono_aot_register_jit_icall ("mono_arm_resume_unwind", mono_arm_resume_unwind);
+
+ if (!mono_aot_only)
+ bp_trampoline = mini_get_breakpoint_trampoline ();
+
+ mono_arm_gsharedvt_init ();
+
+#if defined(TARGET_IOS)
+ ios_abi = TRUE;
+#endif
+}
+
+void
+mono_arch_cleanup (void)
+{
+}
+
+guint32
+mono_arch_cpu_optimizations (guint32 *exclude_mask)
+{
+ *exclude_mask = 0;
+ return 0;
+}
+
+guint32
+mono_arch_cpu_enumerate_simd_versions (void)
+{
+ return 0;
+}
+
+void
+mono_arch_register_lowlevel_calls (void)
+{
+}
+
+void
+mono_arch_finish_init (void)
+{
+}
+
+/* The maximum length is 2 instructions */
+static guint8*
+emit_imm (guint8 *code, int dreg, int imm)
+{
+ // FIXME: Optimize this
+ if (imm < 0) {
+ gint64 limm = imm;
+ arm_movnx (code, dreg, (~limm) & 0xffff, 0);
+ arm_movkx (code, dreg, (limm >> 16) & 0xffff, 16);
+ } else {
+ arm_movzx (code, dreg, imm & 0xffff, 0);
+ if (imm >> 16)
+ arm_movkx (code, dreg, (imm >> 16) & 0xffff, 16);
+ }
+
+ return code;
+}
+
+/* The maximum length is 4 instructions */
+static guint8*
+emit_imm64 (guint8 *code, int dreg, guint64 imm)
+{
+ // FIXME: Optimize this
+ arm_movzx (code, dreg, imm & 0xffff, 0);
+ if ((imm >> 16) & 0xffff)
+ arm_movkx (code, dreg, (imm >> 16) & 0xffff, 16);
+ if ((imm >> 32) & 0xffff)
+ arm_movkx (code, dreg, (imm >> 32) & 0xffff, 32);
+ if ((imm >> 48) & 0xffff)
+ arm_movkx (code, dreg, (imm >> 48) & 0xffff, 48);
+
+ return code;
+}
+
+guint8*
+mono_arm_emit_imm64 (guint8 *code, int dreg, gint64 imm)
+{
+ return emit_imm64 (code, dreg, imm);
+}
+
+/*
+ * emit_imm_template:
+ *
+ * Emit a patchable code sequence for constructing a 64 bit immediate.
+ */
+static guint8*
+emit_imm64_template (guint8 *code, int dreg)
+{
+ arm_movzx (code, dreg, 0, 0);
+ arm_movkx (code, dreg, 0, 16);
+ arm_movkx (code, dreg, 0, 32);
+ arm_movkx (code, dreg, 0, 48);
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_addw_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ if (!arm_is_arith_imm (imm)) {
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_addw (code, dreg, sreg, ARMREG_LR);
+ } else {
+ arm_addw_imm (code, dreg, sreg, imm);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_addx_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ if (!arm_is_arith_imm (imm)) {
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_addx (code, dreg, sreg, ARMREG_LR);
+ } else {
+ arm_addx_imm (code, dreg, sreg, imm);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_subw_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ if (!arm_is_arith_imm (imm)) {
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_subw (code, dreg, sreg, ARMREG_LR);
+ } else {
+ arm_subw_imm (code, dreg, sreg, imm);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_subx_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ if (!arm_is_arith_imm (imm)) {
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_subx (code, dreg, sreg, ARMREG_LR);
+ } else {
+ arm_subx_imm (code, dreg, sreg, imm);
+ }
+ return code;
+}
+
+/* Emit sp+=imm. Clobbers ip0/ip1 */
+static inline __attribute__((warn_unused_result)) guint8*
+emit_addx_sp_imm (guint8 *code, int imm)
+{
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_movspx (code, ARMREG_IP1, ARMREG_SP);
+ arm_addx (code, ARMREG_IP1, ARMREG_IP1, ARMREG_IP0);
+ arm_movspx (code, ARMREG_SP, ARMREG_IP1);
+ return code;
+}
+
+/* Emit sp-=imm. Clobbers ip0/ip1 */
+static inline __attribute__((warn_unused_result)) guint8*
+emit_subx_sp_imm (guint8 *code, int imm)
+{
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_movspx (code, ARMREG_IP1, ARMREG_SP);
+ arm_subx (code, ARMREG_IP1, ARMREG_IP1, ARMREG_IP0);
+ arm_movspx (code, ARMREG_SP, ARMREG_IP1);
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_andw_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ // FIXME:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_andw (code, dreg, sreg, ARMREG_LR);
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_andx_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ // FIXME:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_andx (code, dreg, sreg, ARMREG_LR);
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_orrw_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ // FIXME:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_orrw (code, dreg, sreg, ARMREG_LR);
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_orrx_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ // FIXME:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_orrx (code, dreg, sreg, ARMREG_LR);
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_eorw_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ // FIXME:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_eorw (code, dreg, sreg, ARMREG_LR);
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_eorx_imm (guint8 *code, int dreg, int sreg, int imm)
+{
+ // FIXME:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_eorx (code, dreg, sreg, ARMREG_LR);
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_cmpw_imm (guint8 *code, int sreg, int imm)
+{
+ if (imm == 0) {
+ arm_cmpw (code, sreg, ARMREG_RZR);
+ } else {
+ // FIXME:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_cmpw (code, sreg, ARMREG_LR);
+ }
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_cmpx_imm (guint8 *code, int sreg, int imm)
+{
+ if (imm == 0) {
+ arm_cmpx (code, sreg, ARMREG_RZR);
+ } else {
+ // FIXME:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_cmpx (code, sreg, ARMREG_LR);
+ }
+
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_strb (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_strb_imm (imm)) {
+ arm_strb (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_strb_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_strh (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_strh_imm (imm)) {
+ arm_strh (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_strh_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_strw (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_strw_imm (imm)) {
+ arm_strw (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_strw_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_strfpw (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_strw_imm (imm)) {
+ arm_strfpw (code, rt, rn, imm);
+ } else {
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_addx (code, ARMREG_IP0, rn, ARMREG_IP0);
+ arm_strfpw (code, rt, ARMREG_IP0, 0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_strfpx (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_strx_imm (imm)) {
+ arm_strfpx (code, rt, rn, imm);
+ } else {
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_addx (code, ARMREG_IP0, rn, ARMREG_IP0);
+ arm_strfpx (code, rt, ARMREG_IP0, 0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_strx (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_strx_imm (imm)) {
+ arm_strx (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_strx_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrb (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 1)) {
+ arm_ldrb (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_ldrb_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrsbx (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 1)) {
+ arm_ldrsbx (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_ldrsbx_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrh (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 2)) {
+ arm_ldrh (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_ldrh_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrshx (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 2)) {
+ arm_ldrshx (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_ldrshx_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrswx (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 4)) {
+ arm_ldrswx (code, rt, rn, imm);
+ } else {
+ g_assert (rt != ARMREG_IP0);
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_ldrswx_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrw (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 4)) {
+ arm_ldrw (code, rt, rn, imm);
+ } else {
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_ldrw_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrx (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 8)) {
+ arm_ldrx (code, rt, rn, imm);
+ } else {
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_ldrx_reg (code, rt, rn, ARMREG_IP0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrfpw (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 4)) {
+ arm_ldrfpw (code, rt, rn, imm);
+ } else {
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_addx (code, ARMREG_IP0, rn, ARMREG_IP0);
+ arm_ldrfpw (code, rt, ARMREG_IP0, 0);
+ }
+ return code;
+}
+
+static inline __attribute__((warn_unused_result)) guint8*
+emit_ldrfpx (guint8 *code, int rt, int rn, int imm)
+{
+ if (arm_is_pimm12_scaled (imm, 8)) {
+ arm_ldrfpx (code, rt, rn, imm);
+ } else {
+ g_assert (rn != ARMREG_IP0);
+ code = emit_imm (code, ARMREG_IP0, imm);
+ arm_addx (code, ARMREG_IP0, rn, ARMREG_IP0);
+ arm_ldrfpx (code, rt, ARMREG_IP0, 0);
+ }
+ return code;
+}
+
+guint8*
+mono_arm_emit_ldrx (guint8 *code, int rt, int rn, int imm)
+{
+ return emit_ldrx (code, rt, rn, imm);
+}
+
+static guint8*
+emit_call (MonoCompile *cfg, guint8* code, guint32 patch_type, gconstpointer data)
+{
+ /*
+ mono_add_patch_info_rel (cfg, code - cfg->native_code, patch_type, data, MONO_R_ARM64_IMM);
+ code = emit_imm64_template (code, ARMREG_LR);
+ arm_blrx (code, ARMREG_LR);
+ */
+ mono_add_patch_info_rel (cfg, code - cfg->native_code, patch_type, data, MONO_R_ARM64_BL);
+ arm_bl (code, code);
+ cfg->thunk_area += THUNK_SIZE;
+ return code;
+}
+
+static guint8*
+emit_aotconst_full (MonoCompile *cfg, MonoJumpInfo **ji, guint8 *code, guint8 *start, int dreg, guint32 patch_type, gconstpointer data)
+{
+ if (cfg)
+ mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
+ else
+ *ji = mono_patch_info_list_prepend (*ji, code - start, patch_type, data);
+ /* See arch_emit_got_access () in aot-compiler.c */
+ arm_ldrx_lit (code, dreg, 0);
+ arm_nop (code);
+ arm_nop (code);
+ return code;
+}
+
+static guint8*
+emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, guint32 patch_type, gconstpointer data)
+{
+ return emit_aotconst_full (cfg, NULL, code, NULL, dreg, patch_type, data);
+}
+
+/*
+ * mono_arm_emit_aotconst:
+ *
+ * Emit code to load an AOT constant into DREG. Usable from trampolines.
+ */
+guint8*
+mono_arm_emit_aotconst (gpointer ji, guint8 *code, guint8 *code_start, int dreg, guint32 patch_type, gconstpointer data)
+{
+ return emit_aotconst_full (NULL, (MonoJumpInfo**)ji, code, code_start, dreg, patch_type, data);
+}
+
+static guint8*
+emit_tls_get (guint8 *code, int dreg, int tls_offset)
+{
+ arm_mrs (code, dreg, ARM_MRS_REG_TPIDR_EL0);
+ if (tls_offset < 256) {
+ arm_ldrx (code, dreg, dreg, tls_offset);
+ } else {
+ code = emit_addx_imm (code, dreg, dreg, tls_offset);
+ arm_ldrx (code, dreg, dreg, 0);
+ }
+ return code;
+}
+
+static guint8*
+emit_tls_get_reg (guint8 *code, int dreg, int offset_reg)
+{
+ g_assert (offset_reg != ARMREG_IP0);
+ arm_mrs (code, ARMREG_IP0, ARM_MRS_REG_TPIDR_EL0);
+ arm_ldrx_reg (code, dreg, ARMREG_IP0, offset_reg);
+ return code;
+}
+
+static guint8*
+emit_tls_set (guint8 *code, int sreg, int tls_offset)
+{
+ int tmpreg = ARMREG_IP0;
+
+ g_assert (sreg != tmpreg);
+ arm_mrs (code, tmpreg, ARM_MRS_REG_TPIDR_EL0);
+ if (tls_offset < 256) {
+ arm_strx (code, sreg, tmpreg, tls_offset);
+ } else {
+ code = emit_addx_imm (code, tmpreg, tmpreg, tls_offset);
+ arm_strx (code, sreg, tmpreg, 0);
+ }
+ return code;
+}
+
+
+static guint8*
+emit_tls_set_reg (guint8 *code, int sreg, int offset_reg)
+{
+ int tmpreg = ARMREG_IP0;
+
+ g_assert (sreg != tmpreg);
+ arm_mrs (code, tmpreg, ARM_MRS_REG_TPIDR_EL0);
+ arm_strx_reg (code, sreg, tmpreg, offset_reg);
+ return code;
+}
+
+/*
+ * Emits
+ * - mov sp, fp
+ * - ldrp [fp, lr], [sp], !stack_offfset
+ * Clobbers TEMP_REGS.
+ */
+__attribute__((warn_unused_result)) guint8*
+mono_arm_emit_destroy_frame (guint8 *code, int stack_offset, guint64 temp_regs)
+{
+ arm_movspx (code, ARMREG_SP, ARMREG_FP);
+
+ if (arm_is_ldpx_imm (stack_offset)) {
+ arm_ldpx_post (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, stack_offset);
+ } else {
+ arm_ldpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0);
+ /* sp += stack_offset */
+ g_assert (temp_regs & (1 << ARMREG_IP0));
+ if (temp_regs & (1 << ARMREG_IP1)) {
+ code = emit_addx_sp_imm (code, stack_offset);
+ } else {
+ int imm = stack_offset;
+
+ /* Can't use addx_sp_imm () since we can't clobber ip0/ip1 */
+ arm_addx_imm (code, ARMREG_IP0, ARMREG_SP, 0);
+ while (imm > 256) {
+ arm_addx_imm (code, ARMREG_IP0, ARMREG_IP0, 256);
+ imm -= 256;
+ }
+ arm_addx_imm (code, ARMREG_SP, ARMREG_IP0, imm);
+ }
+ }
+ return code;
+}
+
+#define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
+
+static guint8*
+emit_thunk (guint8 *code, gconstpointer target)
+{
+ guint8 *p = code;
+
+ arm_ldrx_lit (code, ARMREG_IP0, code + 8);
+ arm_brx (code, ARMREG_IP0);
+ *(guint64*)code = (guint64)target;
+
+ mono_arch_flush_icache (p, code - p);
+ return code;
+}
+
+static gpointer
+create_thunk (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target)
+{
+ MonoJitInfo *ji;
+ MonoThunkJitInfo *info;
+ guint8 *thunks, *p;
+ int thunks_size;
+ guint8 *orig_target;
+ guint8 *target_thunk;
+
+ if (!domain)
+ domain = mono_domain_get ();
+
+ if (cfg) {
+ /*
+ * This can be called multiple times during JITting,
+ * save the current position in cfg->arch to avoid
+ * doing a O(n^2) search.
+ */
+ if (!cfg->arch.thunks) {
+ cfg->arch.thunks = cfg->thunks;
+ cfg->arch.thunks_size = cfg->thunk_area;
+ }
+ thunks = cfg->arch.thunks;
+ thunks_size = cfg->arch.thunks_size;
+ if (!thunks_size) {
+ g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, mono_method_full_name (cfg->method, TRUE));
+ g_assert_not_reached ();
+ }
+
+ g_assert (*(guint32*)thunks == 0);
+ emit_thunk (thunks, target);
+
+ cfg->arch.thunks += THUNK_SIZE;
+ cfg->arch.thunks_size -= THUNK_SIZE;
+
+ return thunks;
+ } else {
+ ji = mini_jit_info_table_find (domain, (char*)code, NULL);
+ g_assert (ji);
+ info = mono_jit_info_get_thunk_info (ji);
+ g_assert (info);
+
+ thunks = (guint8*)ji->code_start + info->thunks_offset;
+ thunks_size = info->thunks_size;
+
+ orig_target = mono_arch_get_call_target (code + 4);
+
+ mono_domain_lock (domain);
+
+ target_thunk = NULL;
+ if (orig_target >= thunks && orig_target < thunks + thunks_size) {
+ /* The call already points to a thunk, because of trampolines etc. */
+ target_thunk = orig_target;
+ } else {
+ for (p = thunks; p < thunks + thunks_size; p += THUNK_SIZE) {
+ if (((guint32*)p) [0] == 0) {
+ /* Free entry */
+ target_thunk = p;
+ break;
+ } else if (((guint64*)p) [1] == (guint64)target) {
+ /* Thunk already points to target */
+ target_thunk = p;
+ break;
+ }
+ }
+ }
+
+ //printf ("THUNK: %p %p %p\n", code, target, target_thunk);
+
+ if (!target_thunk) {
+ mono_domain_unlock (domain);
+ g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, cfg ? mono_method_full_name (cfg->method, TRUE) : mono_method_full_name (jinfo_get_method (ji), TRUE));
+ g_assert_not_reached ();
+ }
+
+ emit_thunk (target_thunk, target);
+
+ mono_domain_unlock (domain);
+
+ return target_thunk;
+ }
+}
+
+static void
+arm_patch_full (MonoCompile *cfg, MonoDomain *domain, guint8 *code, guint8 *target, int relocation)
+{
+ switch (relocation) {
+ case MONO_R_ARM64_B:
+ arm_b (code, target);
+ break;
+ case MONO_R_ARM64_BCC: {
+ int cond;
+
+ cond = arm_get_bcc_cond (code);
+ arm_bcc (code, cond, target);
+ break;
+ }
+ case MONO_R_ARM64_CBZ:
+ arm_set_cbz_target (code, target);
+ break;
+ case MONO_R_ARM64_IMM: {
+ guint64 imm = (guint64)target;
+ int dreg;
+
+ /* emit_imm64_template () */
+ dreg = arm_get_movzx_rd (code);
+ arm_movzx (code, dreg, imm & 0xffff, 0);
+ arm_movkx (code, dreg, (imm >> 16) & 0xffff, 16);
+ arm_movkx (code, dreg, (imm >> 32) & 0xffff, 32);
+ arm_movkx (code, dreg, (imm >> 48) & 0xffff, 48);
+ break;
+ }
+ case MONO_R_ARM64_BL:
+ if (arm_is_bl_disp (code, target)) {
+ arm_bl (code, target);
+ } else {
+ gpointer thunk;
+
+ thunk = create_thunk (cfg, domain, code, target);
+ g_assert (arm_is_bl_disp (code, thunk));
+ arm_bl (code, thunk);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+arm_patch_rel (guint8 *code, guint8 *target, int relocation)
+{
+ arm_patch_full (NULL, NULL, code, target, relocation);
+}
+
+void
+mono_arm_patch (guint8 *code, guint8 *target, int relocation)
+{
+ arm_patch_rel (code, target, relocation);
+}
+
+void
+mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target)
+{
+ guint8 *ip;
+
+ ip = ji->ip.i + code;
+
+ switch (ji->type) {
+ case MONO_PATCH_INFO_METHOD_JUMP:
+ /* ji->relocation is not set by the caller */
+ arm_patch_rel (ip, (guint8*)target, MONO_R_ARM64_B);
+ break;
+ default:
+ arm_patch_full (cfg, domain, ip, (guint8*)target, ji->relocation);
+ break;
+ }
+}
+
+void
+mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
+{
+}
+
+void
+mono_arch_flush_register_windows (void)
+{
+}
+
+MonoMethod*
+mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
+{
+ return (gpointer)regs [MONO_ARCH_RGCTX_REG];
+}
+
+MonoVTable*
+mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
+{
+ return (gpointer)regs [MONO_ARCH_RGCTX_REG];
+}
+
+mgreg_t
+mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
+{
+ return ctx->regs [reg];
+}
+
+void
+mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
+{
+ ctx->regs [reg] = val;
+}
+
+/*
+ * mono_arch_set_target:
+ *
+ * Set the target architecture the JIT backend should generate code for, in the form
+ * of a GNU target triplet. Only used in AOT mode.
+ */
+void
+mono_arch_set_target (char *mtriple)
+{
+ if (strstr (mtriple, "darwin") || strstr (mtriple, "ios")) {
+ ios_abi = TRUE;
+ }
+}
+
+static void
+add_general (CallInfo *cinfo, ArgInfo *ainfo, int size, gboolean sign)
+{
+ if (cinfo->gr >= PARAM_REGS) {
+ ainfo->storage = ArgOnStack;
+ if (ios_abi) {
+ /* Assume size == align */
+ cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, size);
+ ainfo->offset = cinfo->stack_usage;
+ ainfo->slot_size = size;
+ ainfo->sign = sign;
+ cinfo->stack_usage += size;
+ } else {
+ ainfo->offset = cinfo->stack_usage;
+ ainfo->slot_size = 8;
+ ainfo->sign = FALSE;
+ /* Put arguments into 8 byte aligned stack slots */
+ cinfo->stack_usage += 8;
+ }
+ } else {
+ ainfo->storage = ArgInIReg;
+ ainfo->reg = cinfo->gr;
+ cinfo->gr ++;
+ }
+}
+
+static void
+add_fp (CallInfo *cinfo, ArgInfo *ainfo, gboolean single)
+{
+ int size = single ? 4 : 8;
+
+ if (cinfo->fr >= FP_PARAM_REGS) {
+ ainfo->storage = single ? ArgOnStackR4 : ArgOnStackR8;
+ if (ios_abi) {
+ cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, size);
+ ainfo->offset = cinfo->stack_usage;
+ ainfo->slot_size = size;
+ cinfo->stack_usage += size;
+ } else {
+ ainfo->offset = cinfo->stack_usage;
+ ainfo->slot_size = 8;
+ /* Put arguments into 8 byte aligned stack slots */
+ cinfo->stack_usage += 8;
+ }
+ } else {
+ if (single)
+ ainfo->storage = ArgInFRegR4;
+ else
+ ainfo->storage = ArgInFReg;
+ ainfo->reg = cinfo->fr;
+ cinfo->fr ++;
+ }
+}
+
+static gboolean
+is_hfa (MonoType *t, int *out_nfields, int *out_esize, int *field_offsets)
+{
+ MonoClass *klass;
+ gpointer iter;
+ MonoClassField *field;
+ MonoType *ftype, *prev_ftype = NULL;
+ int i, nfields = 0;
+
+ klass = mono_class_from_mono_type (t);
+ iter = NULL;
+ while ((field = mono_class_get_fields (klass, &iter))) {
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+ ftype = mono_field_get_type (field);
+ ftype = mini_get_underlying_type (ftype);
+
+ if (MONO_TYPE_ISSTRUCT (ftype)) {
+ int nested_nfields, nested_esize;
+ int nested_field_offsets [16];
+
+ if (!is_hfa (ftype, &nested_nfields, &nested_esize, nested_field_offsets))
+ return FALSE;
+ if (nested_esize == 4)
+ ftype = &mono_defaults.single_class->byval_arg;
+ else
+ ftype = &mono_defaults.double_class->byval_arg;
+ if (prev_ftype && prev_ftype->type != ftype->type)
+ return FALSE;
+ prev_ftype = ftype;
+ for (i = 0; i < nested_nfields; ++i) {
+ if (nfields + i < 4)
+ field_offsets [nfields + i] = field->offset - sizeof (MonoObject) + nested_field_offsets [i];
+ }
+ nfields += nested_nfields;
+ } else {
+ if (!(!ftype->byref && (ftype->type == MONO_TYPE_R4 || ftype->type == MONO_TYPE_R8)))
+ return FALSE;
+ if (prev_ftype && prev_ftype->type != ftype->type)
+ return FALSE;
+ prev_ftype = ftype;
+ if (nfields < 4)
+ field_offsets [nfields] = field->offset - sizeof (MonoObject);
+ nfields ++;
+ }
+ }
+ if (nfields == 0 || nfields > 4)
+ return FALSE;
+ *out_nfields = nfields;
+ *out_esize = prev_ftype->type == MONO_TYPE_R4 ? 4 : 8;
+ return TRUE;
+}
+
+static void
+add_valuetype (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t)
+{
+ int i, size, align_size, nregs, nfields, esize;
+ int field_offsets [16];
+ guint32 align;
+
+ size = mini_type_stack_size_full (t, &align, FALSE);
+ align_size = ALIGN_TO (size, 8);
+
+ nregs = size / 8;
+ if (is_hfa (t, &nfields, &esize, field_offsets)) {
+ /*
+ * The struct might include nested float structs aligned at 8,
+ * so need to keep track of the offsets of the individual fields.
+ */
+ if (cinfo->fr + nfields <= FP_PARAM_REGS) {
+ ainfo->storage = ArgHFA;
+ ainfo->reg = cinfo->fr;
+ ainfo->nregs = nfields;
+ ainfo->size = size;
+ ainfo->esize = esize;
+ for (i = 0; i < nfields; ++i)
+ ainfo->foffsets [i] = field_offsets [i];
+ cinfo->fr += ainfo->nregs;
+ } else {
+ ainfo->nfregs_to_skip = FP_PARAM_REGS > cinfo->fr ? FP_PARAM_REGS - cinfo->fr : 0;
+ cinfo->fr = FP_PARAM_REGS;
+ size = ALIGN_TO (size, 8);
+ ainfo->storage = ArgVtypeOnStack;
+ ainfo->offset = cinfo->stack_usage;
+ ainfo->size = size;
+ ainfo->hfa = TRUE;
+ ainfo->nregs = nfields;
+ ainfo->esize = esize;
+ cinfo->stack_usage += size;
+ }
+ return;
+ }
+
+ if (align_size > 16) {
+ ainfo->storage = ArgVtypeByRef;
+ ainfo->size = size;
+ return;
+ }
+
+ if (cinfo->gr + nregs > PARAM_REGS) {
+ size = ALIGN_TO (size, 8);
+ ainfo->storage = ArgVtypeOnStack;
+ ainfo->offset = cinfo->stack_usage;
+ ainfo->size = size;
+ cinfo->stack_usage += size;
+ cinfo->gr = PARAM_REGS;
+ } else {
+ ainfo->storage = ArgVtypeInIRegs;
+ ainfo->reg = cinfo->gr;
+ ainfo->nregs = nregs;
+ ainfo->size = size;
+ cinfo->gr += nregs;
+ }
+}
+
+static void
+add_param (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t)
+{
+ MonoType *ptype;
+
+ ptype = mini_get_underlying_type (t);
+ switch (ptype->type) {
+ case MONO_TYPE_I1:
+ add_general (cinfo, ainfo, 1, TRUE);
+ break;
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U1:
+ add_general (cinfo, ainfo, 1, FALSE);
+ break;
+ case MONO_TYPE_I2:
+ add_general (cinfo, ainfo, 2, TRUE);
+ break;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ add_general (cinfo, ainfo, 2, FALSE);
+ break;
+ case MONO_TYPE_I4:
+ add_general (cinfo, ainfo, 4, TRUE);
+ break;
+ case MONO_TYPE_U4:
+ add_general (cinfo, ainfo, 4, FALSE);
+ break;
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_FNPTR:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8:
+ add_general (cinfo, ainfo, 8, FALSE);
+ break;
+ case MONO_TYPE_R8:
+ add_fp (cinfo, ainfo, FALSE);
+ break;
+ case MONO_TYPE_R4:
+ add_fp (cinfo, ainfo, TRUE);
+ break;
+ case MONO_TYPE_VALUETYPE:
+ case MONO_TYPE_TYPEDBYREF:
+ add_valuetype (cinfo, ainfo, ptype);
+ break;
+ case MONO_TYPE_VOID:
+ ainfo->storage = ArgNone;
+ break;
+ case MONO_TYPE_GENERICINST:
+ if (!mono_type_generic_inst_is_valuetype (ptype)) {
+ add_general (cinfo, ainfo, 8, FALSE);
+ } else if (mini_is_gsharedvt_variable_type (ptype)) {
+ /*
+ * Treat gsharedvt arguments as large vtypes
+ */
+ ainfo->storage = ArgVtypeByRef;
+ ainfo->gsharedvt = TRUE;
+ } else {
+ add_valuetype (cinfo, ainfo, ptype);
+ }
+ break;
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR:
+ g_assert (mini_is_gsharedvt_type (ptype));
+ ainfo->storage = ArgVtypeByRef;
+ ainfo->gsharedvt = TRUE;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+/*
+ * get_call_info:
+ *
+ * Obtain information about a call according to the calling convention.
+ */
+static CallInfo*
+get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+ CallInfo *cinfo;
+ ArgInfo *ainfo;
+ int n, pstart, pindex;
+
+ n = sig->hasthis + sig->param_count;
+
+ if (mp)
+ cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
+ else
+ cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
+
+ cinfo->nargs = n;
+
+ /* Return value */
+ add_param (cinfo, &cinfo->ret, sig->ret);
+ if (cinfo->ret.storage == ArgVtypeByRef)
+ cinfo->ret.reg = ARMREG_R8;
+ /* Reset state */
+ cinfo->gr = 0;
+ cinfo->fr = 0;
+ cinfo->stack_usage = 0;
+
+ /* Parameters */
+ if (sig->hasthis)
+ add_general (cinfo, cinfo->args + 0, 8, FALSE);
+ pstart = 0;
+ for (pindex = pstart; pindex < sig->param_count; ++pindex) {
+ ainfo = cinfo->args + sig->hasthis + pindex;
+
+ if ((sig->call_convention == MONO_CALL_VARARG) && (pindex == sig->sentinelpos)) {
+ /* Prevent implicit arguments and sig_cookie from
+ being passed in registers */
+ cinfo->gr = PARAM_REGS;
+ cinfo->fr = FP_PARAM_REGS;
+ /* Emit the signature cookie just before the implicit arguments */
+ add_param (cinfo, &cinfo->sig_cookie, &mono_defaults.int_class->byval_arg);
+ }
+
+ add_param (cinfo, ainfo, sig->params [pindex]);
+ if (ainfo->storage == ArgVtypeByRef) {
+ /* Pass the argument address in the next register */
+ if (cinfo->gr >= PARAM_REGS) {
+ ainfo->storage = ArgVtypeByRefOnStack;
+ ainfo->offset = cinfo->stack_usage;
+ cinfo->stack_usage += 8;
+ } else {
+ ainfo->reg = cinfo->gr;
+ cinfo->gr ++;
+ }
+ }
+ }
+
+ /* Handle the case where there are no implicit arguments */
+ if ((sig->call_convention == MONO_CALL_VARARG) && (pindex == sig->sentinelpos)) {
+ /* Prevent implicit arguments and sig_cookie from
+ being passed in registers */
+ cinfo->gr = PARAM_REGS;
+ cinfo->fr = FP_PARAM_REGS;
+ /* Emit the signature cookie just before the implicit arguments */
+ add_param (cinfo, &cinfo->sig_cookie, &mono_defaults.int_class->byval_arg);
+ }
+
+ cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
+
+ return cinfo;
+}
+
+typedef struct {
+ MonoMethodSignature *sig;
+ CallInfo *cinfo;
+ MonoType *rtype;
+ MonoType **param_types;
+ int n_fpargs, n_fpret;
+} ArchDynCallInfo;
+
+static gboolean
+dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
+{
+ int i;
+
+ if (sig->hasthis + sig->param_count > PARAM_REGS + DYN_CALL_STACK_ARGS)
+ return FALSE;
+
+ // FIXME: Add more cases
+ switch (cinfo->ret.storage) {
+ case ArgNone:
+ case ArgInIReg:
+ case ArgInFReg:
+ case ArgInFRegR4:
+ case ArgVtypeByRef:
+ break;
+ case ArgVtypeInIRegs:
+ if (cinfo->ret.nregs > 2)
+ return FALSE;
+ break;
+ case ArgHFA:
+ break;
+ default:
+ return FALSE;
+ }
+
+ for (i = 0; i < cinfo->nargs; ++i) {
+ ArgInfo *ainfo = &cinfo->args [i];
+
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ case ArgVtypeInIRegs:
+ case ArgInFReg:
+ case ArgInFRegR4:
+ case ArgHFA:
+ case ArgVtypeByRef:
+ break;
+ case ArgOnStack:
+ if (ainfo->offset >= DYN_CALL_STACK_ARGS * sizeof (mgreg_t))
+ return FALSE;
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+MonoDynCallInfo*
+mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
+{
+ ArchDynCallInfo *info;
+ CallInfo *cinfo;
+ int i;
+
+ cinfo = get_call_info (NULL, sig);
+
+ if (!dyn_call_supported (cinfo, sig)) {
+ g_free (cinfo);
+ return NULL;
+ }
+
+ info = g_new0 (ArchDynCallInfo, 1);
+ // FIXME: Preprocess the info to speed up start_dyn_call ()
+ info->sig = sig;
+ info->cinfo = cinfo;
+ info->rtype = mini_get_underlying_type (sig->ret);
+ info->param_types = g_new0 (MonoType*, sig->param_count);
+ for (i = 0; i < sig->param_count; ++i)
+ info->param_types [i] = mini_get_underlying_type (sig->params [i]);
+
+ switch (cinfo->ret.storage) {
+ case ArgInFReg:
+ case ArgInFRegR4:
+ info->n_fpret = 1;
+ break;
+ case ArgHFA:
+ info->n_fpret = cinfo->ret.nregs;
+ break;
+ default:
+ break;
+ }
+
+ return (MonoDynCallInfo*)info;
+}
+
+void
+mono_arch_dyn_call_free (MonoDynCallInfo *info)
+{
+ ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
+
+ g_free (ainfo->cinfo);
+ g_free (ainfo->param_types);
+ g_free (ainfo);
+}
+
+static double
+bitcast_r4_to_r8 (float f)
+{
+ float *p = &f;
+
+ return *(double*)p;
+}
+
+static float
+bitcast_r8_to_r4 (double f)
+{
+ double *p = &f;
+
+ return *(float*)p;
+}
+
+void
+mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len)
+{
+ ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
+ DynCallArgs *p = (DynCallArgs*)buf;
+ int aindex, arg_index, greg, i, pindex;
+ MonoMethodSignature *sig = dinfo->sig;
+ CallInfo *cinfo = dinfo->cinfo;
+ int buffer_offset = 0;
+
+ g_assert (buf_len >= sizeof (DynCallArgs));
+
+ p->res = 0;
+ p->ret = ret;
+ p->n_fpargs = dinfo->n_fpargs;
+ p->n_fpret = dinfo->n_fpret;
+
+ arg_index = 0;
+ greg = 0;
+ pindex = 0;
+
+ if (sig->hasthis)
+ p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);
+
+ if (cinfo->ret.storage == ArgVtypeByRef)
+ p->regs [ARMREG_R8] = (mgreg_t)ret;
+
+ for (aindex = pindex; aindex < sig->param_count; aindex++) {
+ MonoType *t = dinfo->param_types [aindex];
+ gpointer *arg = args [arg_index ++];
+ ArgInfo *ainfo = &cinfo->args [aindex + sig->hasthis];
+ int slot = -1;
+
+ if (ainfo->storage == ArgOnStack) {
+ slot = PARAM_REGS + 1 + (ainfo->offset / sizeof (mgreg_t));
+ } else {
+ slot = ainfo->reg;
+ }
+
+ if (t->byref) {
+ p->regs [slot] = (mgreg_t)*arg;
+ continue;
+ }
+
+ if (ios_abi && ainfo->storage == ArgOnStack) {
+ guint8 *stack_arg = (guint8*)&(p->regs [PARAM_REGS + 1]) + ainfo->offset;
+ gboolean handled = TRUE;
+
+ /* Special case arguments smaller than 1 machine word */
+ switch (t->type) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U1:
+ *(guint8*)stack_arg = *(guint8*)arg;
+ break;
+ case MONO_TYPE_I1:
+ *(gint8*)stack_arg = *(gint8*)arg;
+ break;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ *(guint16*)stack_arg = *(guint16*)arg;
+ break;
+ case MONO_TYPE_I2:
+ *(gint16*)stack_arg = *(gint16*)arg;
+ break;
+ case MONO_TYPE_I4:
+ *(gint32*)stack_arg = *(gint32*)arg;
+ break;
+ case MONO_TYPE_U4:
+ *(guint32*)stack_arg = *(guint32*)arg;
+ break;
+ default:
+ handled = FALSE;
+ break;
+ }
+ if (handled)
+ continue;
+ }
+
+ switch (t->type) {
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ p->regs [slot] = (mgreg_t)*arg;
+ break;
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U1:
+ p->regs [slot] = *(guint8*)arg;
+ break;
+ case MONO_TYPE_I1:
+ p->regs [slot] = *(gint8*)arg;
+ break;
+ case MONO_TYPE_I2:
+ p->regs [slot] = *(gint16*)arg;
+ break;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ p->regs [slot] = *(guint16*)arg;
+ break;
+ case MONO_TYPE_I4:
+ p->regs [slot] = *(gint32*)arg;
+ break;
+ case MONO_TYPE_U4:
+ p->regs [slot] = *(guint32*)arg;
+ break;
+ case MONO_TYPE_R4:
+ p->fpregs [ainfo->reg] = bitcast_r4_to_r8 (*(float*)arg);
+ p->n_fpargs ++;
+ break;
+ case MONO_TYPE_R8:
+ p->fpregs [ainfo->reg] = *(double*)arg;
+ p->n_fpargs ++;
+ break;
+ case MONO_TYPE_GENERICINST:
+ if (MONO_TYPE_IS_REFERENCE (t)) {
+ p->regs [slot] = (mgreg_t)*arg;
+ break;
+ } else {
+ if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ MonoClass *klass = mono_class_from_mono_type (t);
+ guint8 *nullable_buf;
+ int size;
+
+ /*
+ * Use p->buffer as a temporary buffer since the data needs to be available after this call
+ * if the nullable param is passed by ref.
+ */
+ size = mono_class_value_size (klass, NULL);
+ nullable_buf = p->buffer + buffer_offset;
+ buffer_offset += size;
+ g_assert (buffer_offset <= 256);
+
+ /* The argument pointed to by arg is either a boxed vtype or null */
+ mono_nullable_init (nullable_buf, (MonoObject*)arg, klass);
+
+ arg = (gpointer*)nullable_buf;
+ /* Fall though */
+ } else {
+ /* Fall though */
+ }
+ }
+ case MONO_TYPE_VALUETYPE:
+ switch (ainfo->storage) {
+ case ArgVtypeInIRegs:
+ for (i = 0; i < ainfo->nregs; ++i)
+ p->regs [slot ++] = ((mgreg_t*)arg) [i];
+ break;
+ case ArgHFA:
+ if (ainfo->esize == 4) {
+ for (i = 0; i < ainfo->nregs; ++i)
+ p->fpregs [ainfo->reg + i] = bitcast_r4_to_r8 (((float*)arg) [ainfo->foffsets [i] / 4]);
+ } else {
+ for (i = 0; i < ainfo->nregs; ++i)
+ p->fpregs [ainfo->reg + i] = ((double*)arg) [ainfo->foffsets [i] / 8];
+ }
+ p->n_fpargs += ainfo->nregs;
+ break;
+ case ArgVtypeByRef:
+ p->regs [slot] = (mgreg_t)arg;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+}
+
+void
+mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
+{
+ ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
+ CallInfo *cinfo = ainfo->cinfo;
+ DynCallArgs *args = (DynCallArgs*)buf;
+ MonoType *ptype = ainfo->rtype;
+ guint8 *ret = args->ret;
+ mgreg_t res = args->res;
+ mgreg_t res2 = args->res2;
+ int i;
+
+ if (cinfo->ret.storage == ArgVtypeByRef)
+ return;
+
+ switch (ptype->type) {
+ case MONO_TYPE_VOID:
+ *(gpointer*)ret = NULL;
+ break;
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ *(gpointer*)ret = (gpointer)res;
+ break;
+ case MONO_TYPE_I1:
+ *(gint8*)ret = res;
+ break;
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ *(guint8*)ret = res;
+ break;
+ case MONO_TYPE_I2:
+ *(gint16*)ret = res;
+ break;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ *(guint16*)ret = res;
+ break;
+ case MONO_TYPE_I4:
+ *(gint32*)ret = res;
+ break;
+ case MONO_TYPE_U4:
+ *(guint32*)ret = res;
+ break;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ *(guint64*)ret = res;
+ break;
+ case MONO_TYPE_R4:
+ *(float*)ret = bitcast_r8_to_r4 (args->fpregs [0]);
+ break;
+ case MONO_TYPE_R8:
+ *(double*)ret = args->fpregs [0];
+ break;
+ case MONO_TYPE_GENERICINST:
+ if (MONO_TYPE_IS_REFERENCE (ptype)) {
+ *(gpointer*)ret = (gpointer)res;
+ break;
+ } else {
+ /* Fall though */
+ }
+ case MONO_TYPE_VALUETYPE:
+ switch (ainfo->cinfo->ret.storage) {
+ case ArgVtypeInIRegs:
+ *(mgreg_t*)ret = res;
+ if (ainfo->cinfo->ret.nregs > 1)
+ ((mgreg_t*)ret) [1] = res2;
+ break;
+ case ArgHFA:
+ /* Use the same area for returning fp values */
+ if (cinfo->ret.esize == 4) {
+ for (i = 0; i < cinfo->ret.nregs; ++i)
+ ((float*)ret) [cinfo->ret.foffsets [i] / 4] = bitcast_r8_to_r4 (args->fpregs [i]);
+ } else {
+ for (i = 0; i < cinfo->ret.nregs; ++i)
+ ((double*)ret) [cinfo->ret.foffsets [i] / 8] = args->fpregs [i];
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+#if __APPLE__
+void sys_icache_invalidate (void *start, size_t len);
+#endif
+
+void
+mono_arch_flush_icache (guint8 *code, gint size)
+{
+#ifndef MONO_CROSS_COMPILE
+#if __APPLE__
+ sys_icache_invalidate (code, size);
+#else
+ __clear_cache (code, code + size);
+#endif
+#endif
+}
+
+#ifndef DISABLE_JIT
+
+gboolean
+mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode)
+{
+ NOT_IMPLEMENTED;
+ return FALSE;
+}
+
+GList *
+mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
+{
+ GList *vars = NULL;
+ int i;
+
+ for (i = 0; i < cfg->num_varinfo; i++) {
+ MonoInst *ins = cfg->varinfo [i];
+ MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
+
+ /* unused vars */
+ if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
+ continue;
+
+ if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
+ (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
+ continue;
+
+ if (mono_is_regsize_var (ins->inst_vtype)) {
+ g_assert (MONO_VARINFO (cfg, i)->reg == -1);
+ g_assert (i == vmv->idx);
+ vars = g_list_prepend (vars, vmv);
+ }
+ }
+
+ vars = mono_varlist_sort (cfg, vars, 0);
+
+ return vars;
+}
+
+GList *
+mono_arch_get_global_int_regs (MonoCompile *cfg)
+{
+ GList *regs = NULL;
+ int i;
+
+ /* r28 is reserved for cfg->arch.args_reg */
+ /* r27 is reserved for the imt argument */
+ for (i = ARMREG_R19; i <= ARMREG_R26; ++i)
+ regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
+
+ return regs;
+}
+
+guint32
+mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
+{
+ MonoInst *ins = cfg->varinfo [vmv->idx];
+
+ if (ins->opcode == OP_ARG)
+ return 1;
+ else
+ return 2;
+}
+
+void
+mono_arch_create_vars (MonoCompile *cfg)
+{
+ MonoMethodSignature *sig;
+ CallInfo *cinfo;
+
+ sig = mono_method_signature (cfg->method);
+ if (!cfg->arch.cinfo)
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
+ cinfo = cfg->arch.cinfo;
+
+ if (cinfo->ret.storage == ArgVtypeByRef) {
+ cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ cfg->vret_addr->flags |= MONO_INST_VOLATILE;
+ }
+
+ if (cfg->gen_sdb_seq_points) {
+ MonoInst *ins;
+
+ if (cfg->compile_aot) {
+ ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ ins->flags |= MONO_INST_VOLATILE;
+ cfg->arch.seq_point_info_var = ins;
+ }
+
+ ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ ins->flags |= MONO_INST_VOLATILE;
+ cfg->arch.ss_tramp_var = ins;
+
+ ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ ins->flags |= MONO_INST_VOLATILE;
+ cfg->arch.bp_tramp_var = ins;
+ }
+
+ if (cfg->method->save_lmf) {
+ cfg->create_lmf_var = TRUE;
+ cfg->lmf_ir = TRUE;
+#ifndef TARGET_MACH
+ cfg->lmf_ir_mono_lmf = TRUE;
+#endif
+ }
+}
+
+void
+mono_arch_allocate_vars (MonoCompile *cfg)
+{
+ MonoMethodSignature *sig;
+ MonoInst *ins;
+ CallInfo *cinfo;
+ ArgInfo *ainfo;
+ int i, offset, size, align;
+ guint32 locals_stack_size, locals_stack_align;
+ gint32 *offsets;
+
+ /*
+ * Allocate arguments and locals to either register (OP_REGVAR) or to a stack slot (OP_REGOFFSET).
+ * Compute cfg->stack_offset and update cfg->used_int_regs.
+ */
+
+ sig = mono_method_signature (cfg->method);
+
+ if (!cfg->arch.cinfo)
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
+ cinfo = cfg->arch.cinfo;
+
+ /*
+ * The ARM64 ABI always uses a frame pointer.
+ * The instruction set prefers positive offsets, so fp points to the bottom of the
+ * frame, and stack slots are at positive offsets.
+ * If some arguments are received on the stack, their offsets relative to fp can
+ * not be computed right now because the stack frame might grow due to spilling
+ * done by the local register allocator. To solve this, we reserve a register
+ * which points to them.
+ * The stack frame looks like this:
+ * args_reg -> <bottom of parent frame>
+ * <locals etc>
+ * fp -> <saved fp+lr>
+ * sp -> <localloc/params area>
+ */
+ cfg->frame_reg = ARMREG_FP;
+ cfg->flags |= MONO_CFG_HAS_SPILLUP;
+ offset = 0;
+
+ /* Saved fp+lr */
+ offset += 16;
+
+ if (cinfo->stack_usage) {
+ g_assert (!(cfg->used_int_regs & (1 << ARMREG_R28)));
+ cfg->arch.args_reg = ARMREG_R28;
+ cfg->used_int_regs |= 1 << ARMREG_R28;
+ }
+
+ if (cfg->method->save_lmf) {
+ /* The LMF var is allocated normally */
+ } else {
+ /* Callee saved regs */
+ cfg->arch.saved_gregs_offset = offset;
+ for (i = 0; i < 32; ++i)
+ if ((MONO_ARCH_CALLEE_SAVED_REGS & (1 << i)) && (cfg->used_int_regs & (1 << i)))
+ offset += 8;
+ }
+
+ /* Return value */
+ switch (cinfo->ret.storage) {
+ case ArgNone:
+ break;
+ case ArgInIReg:
+ case ArgInFReg:
+ case ArgInFRegR4:
+ cfg->ret->opcode = OP_REGVAR;
+ cfg->ret->dreg = cinfo->ret.reg;
+ break;
+ case ArgVtypeInIRegs:
+ case ArgHFA:
+ /* Allocate a local to hold the result, the epilog will copy it to the correct place */
+ cfg->ret->opcode = OP_REGOFFSET;
+ cfg->ret->inst_basereg = cfg->frame_reg;
+ cfg->ret->inst_offset = offset;
+ if (cinfo->ret.storage == ArgHFA)
+ // FIXME:
+ offset += 64;
+ else
+ offset += 16;
+ break;
+ case ArgVtypeByRef:
+ /* This variable will be initalized in the prolog from R8 */
+ cfg->vret_addr->opcode = OP_REGOFFSET;
+ cfg->vret_addr->inst_basereg = cfg->frame_reg;
+ cfg->vret_addr->inst_offset = offset;
+ offset += 8;
+ if (G_UNLIKELY (cfg->verbose_level > 1)) {
+ printf ("vret_addr =");
+ mono_print_ins (cfg->vret_addr);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* Arguments */
+ for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+ ainfo = cinfo->args + i;
+
+ ins = cfg->args [i];
+ if (ins->opcode == OP_REGVAR)
+ continue;
+
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = cfg->frame_reg;
+
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ case ArgInFReg:
+ case ArgInFRegR4:
+ // FIXME: Use nregs/size
+ /* These will be copied to the stack in the prolog */
+ ins->inst_offset = offset;
+ offset += 8;
+ break;
+ case ArgOnStack:
+ case ArgOnStackR4:
+ case ArgOnStackR8:
+ case ArgVtypeOnStack:
+ /* These are in the parent frame */
+ g_assert (cfg->arch.args_reg);
+ ins->inst_basereg = cfg->arch.args_reg;
+ ins->inst_offset = ainfo->offset;
+ break;
+ case ArgVtypeInIRegs:
+ case ArgHFA:
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = cfg->frame_reg;
+ /* These arguments are saved to the stack in the prolog */
+ ins->inst_offset = offset;
+ if (cfg->verbose_level >= 2)
+ printf ("arg %d allocated to %s+0x%0x.\n", i, mono_arch_regname (ins->inst_basereg), (int)ins->inst_offset);
+ if (ainfo->storage == ArgHFA)
+ // FIXME:
+ offset += 64;
+ else
+ offset += 16;
+ break;
+ case ArgVtypeByRefOnStack: {
+ MonoInst *vtaddr;
+
+ if (ainfo->gsharedvt) {
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = cfg->arch.args_reg;
+ ins->inst_offset = ainfo->offset;
+ break;
+ }
+
+ /* The vtype address is in the parent frame */
+ g_assert (cfg->arch.args_reg);
+ MONO_INST_NEW (cfg, vtaddr, 0);
+ vtaddr->opcode = OP_REGOFFSET;
+ vtaddr->inst_basereg = cfg->arch.args_reg;
+ vtaddr->inst_offset = ainfo->offset;
+
+ /* Need an indirection */
+ ins->opcode = OP_VTARG_ADDR;
+ ins->inst_left = vtaddr;
+ break;
+ }
+ case ArgVtypeByRef: {
+ MonoInst *vtaddr;
+
+ if (ainfo->gsharedvt) {
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = cfg->frame_reg;
+ ins->inst_offset = offset;
+ offset += 8;
+ break;
+ }
+
+ /* The vtype address is in a register, will be copied to the stack in the prolog */
+ MONO_INST_NEW (cfg, vtaddr, 0);
+ vtaddr->opcode = OP_REGOFFSET;
+ vtaddr->inst_basereg = cfg->frame_reg;
+ vtaddr->inst_offset = offset;
+ offset += 8;
+
+ /* Need an indirection */
+ ins->opcode = OP_VTARG_ADDR;
+ ins->inst_left = vtaddr;
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ /* Allocate these first so they have a small offset, OP_SEQ_POINT depends on this */
+ // FIXME: Allocate these to registers
+ ins = cfg->arch.seq_point_info_var;
+ if (ins) {
+ size = 8;
+ align = 8;
+ offset += align - 1;
+ offset &= ~(align - 1);
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = cfg->frame_reg;
+ ins->inst_offset = offset;
+ offset += size;
+ }
+ ins = cfg->arch.ss_tramp_var;
+ if (ins) {
+ size = 8;
+ align = 8;
+ offset += align - 1;
+ offset &= ~(align - 1);
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = cfg->frame_reg;
+ ins->inst_offset = offset;
+ offset += size;
+ }
+ ins = cfg->arch.bp_tramp_var;
+ if (ins) {
+ size = 8;
+ align = 8;
+ offset += align - 1;
+ offset &= ~(align - 1);
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = cfg->frame_reg;
+ ins->inst_offset = offset;
+ offset += size;
+ }
+
+ /* Locals */
+ offsets = mono_allocate_stack_slots (cfg, FALSE, &locals_stack_size, &locals_stack_align);
+ if (locals_stack_align)
+ offset = ALIGN_TO (offset, locals_stack_align);
+
+ for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
+ if (offsets [i] != -1) {
+ ins = cfg->varinfo [i];
+ ins->opcode = OP_REGOFFSET;
+ ins->inst_basereg = cfg->frame_reg;
+ ins->inst_offset = offset + offsets [i];
+ //printf ("allocated local %d to ", i); mono_print_tree_nl (ins);
+ }
+ }
+ offset += locals_stack_size;
+
+ offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+
+ cfg->stack_offset = offset;
+}
+
+#ifdef ENABLE_LLVM
+LLVMCallInfo*
+mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
+{
+ int i, n;
+ CallInfo *cinfo;
+ ArgInfo *ainfo;
+ LLVMCallInfo *linfo;
+
+ n = sig->param_count + sig->hasthis;
+
+ cinfo = get_call_info (cfg->mempool, sig);
+
+ linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
+
+ switch (cinfo->ret.storage) {
+ case ArgInIReg:
+ case ArgInFReg:
+ case ArgInFRegR4:
+ case ArgNone:
+ break;
+ case ArgVtypeByRef:
+ linfo->ret.storage = LLVMArgVtypeByRef;
+ break;
+ //
+ // FIXME: This doesn't work yet since the llvm backend represents these types as an i8
+ // array which is returned in int regs
+ //
+ case ArgHFA:
+ linfo->ret.storage = LLVMArgFpStruct;
+ linfo->ret.nslots = cinfo->ret.nregs;
+ linfo->ret.esize = cinfo->ret.esize;
+ break;
+ case ArgVtypeInIRegs:
+ /* LLVM models this by returning an int */
+ linfo->ret.storage = LLVMArgVtypeAsScalar;
+ linfo->ret.nslots = cinfo->ret.nregs;
+ linfo->ret.esize = cinfo->ret.esize;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ for (i = 0; i < n; ++i) {
+ LLVMArgInfo *lainfo = &linfo->args [i];
+
+ ainfo = cinfo->args + i;
+
+ lainfo->storage = LLVMArgNone;
+
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ case ArgInFReg:
+ case ArgInFRegR4:
+ case ArgOnStack:
+ case ArgOnStackR4:
+ case ArgOnStackR8:
+ lainfo->storage = LLVMArgNormal;
+ break;
+ case ArgVtypeByRef:
+ case ArgVtypeByRefOnStack:
+ lainfo->storage = LLVMArgVtypeByRef;
+ break;
+ case ArgHFA: {
+ int j;
+
+ lainfo->storage = LLVMArgAsFpArgs;
+ lainfo->nslots = ainfo->nregs;
+ lainfo->esize = ainfo->esize;
+ for (j = 0; j < ainfo->nregs; ++j)
+ lainfo->pair_storage [j] = LLVMArgInFPReg;
+ break;
+ }
+ case ArgVtypeInIRegs:
+ lainfo->storage = LLVMArgAsIArgs;
+ lainfo->nslots = ainfo->nregs;
+ break;
+ case ArgVtypeOnStack:
+ if (ainfo->hfa) {
+ int j;
+ /* Same as above */
+ lainfo->storage = LLVMArgAsFpArgs;
+ lainfo->nslots = ainfo->nregs;
+ lainfo->esize = ainfo->esize;
+ lainfo->ndummy_fpargs = ainfo->nfregs_to_skip;
+ for (j = 0; j < ainfo->nregs; ++j)
+ lainfo->pair_storage [j] = LLVMArgInFPReg;
+ } else {
+ lainfo->storage = LLVMArgAsIArgs;
+ lainfo->nslots = ainfo->size / 8;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ return linfo;
+}
+#endif
+
+static void
+add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *arg)
+{
+ MonoInst *ins;
+
+ switch (storage) {
+ case ArgInIReg:
+ MONO_INST_NEW (cfg, ins, OP_MOVE);
+ ins->dreg = mono_alloc_ireg_copy (cfg, arg->dreg);
+ ins->sreg1 = arg->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, FALSE);
+ break;
+ case ArgInFReg:
+ MONO_INST_NEW (cfg, ins, OP_FMOVE);
+ ins->dreg = mono_alloc_freg (cfg);
+ ins->sreg1 = arg->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
+ break;
+ case ArgInFRegR4:
+ if (COMPILE_LLVM (cfg))
+ MONO_INST_NEW (cfg, ins, OP_FMOVE);
+ else if (cfg->r4fp)
+ MONO_INST_NEW (cfg, ins, OP_RMOVE);
+ else
+ MONO_INST_NEW (cfg, ins, OP_ARM_SETFREG_R4);
+ ins->dreg = mono_alloc_freg (cfg);
+ ins->sreg1 = arg->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
+{
+ MonoMethodSignature *tmp_sig;
+ int sig_reg;
+
+ if (call->tail_call)
+ NOT_IMPLEMENTED;
+
+ g_assert (cinfo->sig_cookie.storage == ArgOnStack);
+
+ /*
+ * mono_ArgIterator_Setup assumes the signature cookie is
+ * passed first and all the arguments which were before it are
+ * passed on the stack after the signature. So compensate by
+ * passing a different signature.
+ */
+ tmp_sig = mono_metadata_signature_dup (call->signature);
+ tmp_sig->param_count -= call->signature->sentinelpos;
+ tmp_sig->sentinelpos = 0;
+ memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
+
+ sig_reg = mono_alloc_ireg (cfg);
+ MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig);
+
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, cinfo->sig_cookie.offset, sig_reg);
+}
+
+void
+mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
+{
+ MonoMethodSignature *sig;
+ MonoInst *arg, *vtarg;
+ CallInfo *cinfo;
+ ArgInfo *ainfo;
+ int i;
+
+ sig = call->signature;
+
+ cinfo = get_call_info (cfg->mempool, sig);
+
+ switch (cinfo->ret.storage) {
+ case ArgVtypeInIRegs:
+ case ArgHFA:
+ /*
+ * The vtype is returned in registers, save the return area address in a local, and save the vtype into
+ * the location pointed to by it after call in emit_move_return_value ().
+ */
+ if (!cfg->arch.vret_addr_loc) {
+ cfg->arch.vret_addr_loc = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ /* Prevent it from being register allocated or optimized away */
+ ((MonoInst*)cfg->arch.vret_addr_loc)->flags |= MONO_INST_VOLATILE;
+ }
+
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ((MonoInst*)cfg->arch.vret_addr_loc)->dreg, call->vret_var->dreg);
+ break;
+ case ArgVtypeByRef:
+ /* Pass the vtype return address in R8 */
+ MONO_INST_NEW (cfg, vtarg, OP_MOVE);
+ vtarg->sreg1 = call->vret_var->dreg;
+ vtarg->dreg = mono_alloc_preg (cfg);
+ MONO_ADD_INS (cfg->cbb, vtarg);
+
+ mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < cinfo->nargs; ++i) {
+ ainfo = cinfo->args + i;
+ arg = call->args [i];
+
+ if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
+ /* Emit the signature cookie just before the implicit arguments */
+ emit_sig_cookie (cfg, call, cinfo);
+ }
+
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ case ArgInFReg:
+ case ArgInFRegR4:
+ add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, arg);
+ break;
+ case ArgOnStack:
+ switch (ainfo->slot_size) {
+ case 8:
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
+ break;
+ case 4:
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
+ break;
+ case 2:
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
+ break;
+ case 1:
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+ case ArgOnStackR8:
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
+ break;
+ case ArgOnStackR4:
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
+ break;
+ case ArgVtypeInIRegs:
+ case ArgVtypeByRef:
+ case ArgVtypeByRefOnStack:
+ case ArgVtypeOnStack:
+ case ArgHFA: {
+ MonoInst *ins;
+ guint32 align;
+ guint32 size;
+
+ size = mono_class_value_size (arg->klass, &align);
+
+ MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
+ ins->sreg1 = arg->dreg;
+ ins->klass = arg->klass;
+ ins->backend.size = size;
+ ins->inst_p0 = call;
+ ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
+ memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
+ MONO_ADD_INS (cfg->cbb, ins);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ /* Handle the case where there are no implicit arguments */
+ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (cinfo->nargs == sig->sentinelpos))
+ emit_sig_cookie (cfg, call, cinfo);
+
+ call->call_info = cinfo;
+ call->stack_usage = cinfo->stack_usage;
+}
+
+void
+mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
+{
+ MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
+ ArgInfo *ainfo = ins->inst_p1;
+ MonoInst *load;
+ int i;
+
+ if (ins->backend.size == 0 && !ainfo->gsharedvt)
+ return;
+
+ switch (ainfo->storage) {
+ case ArgVtypeInIRegs:
+ for (i = 0; i < ainfo->nregs; ++i) {
+ // FIXME: Smaller sizes
+ MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
+ load->dreg = mono_alloc_ireg (cfg);
+ load->inst_basereg = src->dreg;
+ load->inst_offset = i * sizeof(mgreg_t);
+ MONO_ADD_INS (cfg->cbb, load);
+ add_outarg_reg (cfg, call, ArgInIReg, ainfo->reg + i, load);
+ }
+ break;
+ case ArgHFA:
+ for (i = 0; i < ainfo->nregs; ++i) {
+ if (ainfo->esize == 4)
+ MONO_INST_NEW (cfg, load, OP_LOADR4_MEMBASE);
+ else
+ MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
+ load->dreg = mono_alloc_freg (cfg);
+ load->inst_basereg = src->dreg;
+ load->inst_offset = ainfo->foffsets [i];
+ MONO_ADD_INS (cfg->cbb, load);
+ add_outarg_reg (cfg, call, ainfo->esize == 4 ? ArgInFRegR4 : ArgInFReg, ainfo->reg + i, load);
+ }
+ break;
+ case ArgVtypeByRef:
+ case ArgVtypeByRefOnStack: {
+ MonoInst *vtaddr, *load, *arg;
+
+ /* Pass the vtype address in a reg/on the stack */
+ if (ainfo->gsharedvt) {
+ load = src;
+ } else {
+ /* Make a copy of the argument */
+ vtaddr = mono_compile_create_var (cfg, &ins->klass->byval_arg, OP_LOCAL);
+
+ MONO_INST_NEW (cfg, load, OP_LDADDR);
+ load->inst_p0 = vtaddr;
+ vtaddr->flags |= MONO_INST_INDIRECT;
+ load->type = STACK_MP;
+ load->klass = vtaddr->klass;
+ load->dreg = mono_alloc_ireg (cfg);
+ MONO_ADD_INS (cfg->cbb, load);
+ mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, ainfo->size, 8);
+ }
+
+ if (ainfo->storage == ArgVtypeByRef) {
+ MONO_INST_NEW (cfg, arg, OP_MOVE);
+ arg->dreg = mono_alloc_preg (cfg);
+ arg->sreg1 = load->dreg;
+ MONO_ADD_INS (cfg->cbb, arg);
+ add_outarg_reg (cfg, call, ArgInIReg, ainfo->reg, arg);
+ } else {
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, load->dreg);
+ }
+ break;
+ }
+ case ArgVtypeOnStack:
+ for (i = 0; i < ainfo->size / 8; ++i) {
+ MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
+ load->dreg = mono_alloc_ireg (cfg);
+ load->inst_basereg = src->dreg;
+ load->inst_offset = i * 8;
+ MONO_ADD_INS (cfg->cbb, load);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ARMREG_SP, ainfo->offset + (i * 8), load->dreg);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+void
+mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
+{
+ MonoMethodSignature *sig;
+ CallInfo *cinfo;
+
+ sig = mono_method_signature (cfg->method);
+ if (!cfg->arch.cinfo)
+ cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
+ cinfo = cfg->arch.cinfo;
+
+ switch (cinfo->ret.storage) {
+ case ArgNone:
+ break;
+ case ArgInIReg:
+ MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
+ break;
+ case ArgInFReg:
+ MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
+ break;
+ case ArgInFRegR4:
+ if (COMPILE_LLVM (cfg))
+ MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
+ else if (cfg->r4fp)
+ MONO_EMIT_NEW_UNALU (cfg, OP_RMOVE, cfg->ret->dreg, val->dreg);
+ else
+ MONO_EMIT_NEW_UNALU (cfg, OP_ARM_SETFREG_R4, cfg->ret->dreg, val->dreg);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+gboolean
+mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
+{
+ CallInfo *c1, *c2;
+ gboolean res;
+
+ if (cfg->compile_aot && !cfg->full_aot)
+ /* OP_TAILCALL doesn't work with AOT */
+ return FALSE;
+
+ c1 = get_call_info (NULL, caller_sig);
+ c2 = get_call_info (NULL, callee_sig);
+ res = TRUE;
+ // FIXME: Relax these restrictions
+ if (c1->stack_usage != 0)
+ res = FALSE;
+ if (c1->stack_usage != c2->stack_usage)
+ res = FALSE;
+ if ((c1->ret.storage != ArgNone && c1->ret.storage != ArgInIReg) || c1->ret.storage != c2->ret.storage)
+ res = FALSE;
+
+ g_free (c1);
+ g_free (c2);
+
+ return res;
+}
+
+gboolean
+mono_arch_is_inst_imm (gint64 imm)
+{
+ return (imm >= -((gint64)1<<31) && imm <= (((gint64)1<<31)-1));
+}
+
+void*
+mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
+{
+ NOT_IMPLEMENTED;
+ return NULL;
+}
+
+void*
+mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
+{
+ NOT_IMPLEMENTED;
+ return NULL;
+}
+
+void
+mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ //NOT_IMPLEMENTED;
+}
+
+void
+mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ //NOT_IMPLEMENTED;
+}
+
+#define ADD_NEW_INS(cfg,dest,op) do { \
+ MONO_INST_NEW ((cfg), (dest), (op)); \
+ mono_bblock_insert_before_ins (bb, ins, (dest)); \
+ } while (0)
+
+void
+mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ MonoInst *ins, *temp, *last_ins = NULL;
+
+ MONO_BB_FOR_EACH_INS (bb, ins) {
+ switch (ins->opcode) {
+ case OP_SBB:
+ case OP_ISBB:
+ case OP_SUBCC:
+ case OP_ISUBCC:
+ if (ins->next && (ins->next->opcode == OP_COND_EXC_C || ins->next->opcode == OP_COND_EXC_IC))
+ /* ARM sets the C flag to 1 if there was _no_ overflow */
+ ins->next->opcode = OP_COND_EXC_NC;
+ break;
+ case OP_IDIV_IMM:
+ case OP_IREM_IMM:
+ case OP_IDIV_UN_IMM:
+ case OP_IREM_UN_IMM:
+ case OP_LREM_IMM:
+ mono_decompose_op_imm (cfg, bb, ins);
+ break;
+ case OP_LOCALLOC_IMM:
+ if (ins->inst_imm > 32) {
+ ADD_NEW_INS (cfg, temp, OP_ICONST);
+ temp->inst_c0 = ins->inst_imm;
+ temp->dreg = mono_alloc_ireg (cfg);
+ ins->sreg1 = temp->dreg;
+ ins->opcode = mono_op_imm_to_op (ins->opcode);
+ }
+ break;
+ case OP_ICOMPARE_IMM:
+ if (ins->inst_imm == 0 && ins->next && ins->next->opcode == OP_IBEQ) {
+ ins->next->opcode = OP_ARM64_CBZW;
+ ins->next->sreg1 = ins->sreg1;
+ NULLIFY_INS (ins);
+ } else if (ins->inst_imm == 0 && ins->next && ins->next->opcode == OP_IBNE_UN) {
+ ins->next->opcode = OP_ARM64_CBNZW;
+ ins->next->sreg1 = ins->sreg1;
+ NULLIFY_INS (ins);
+ }
+ break;
+ case OP_LCOMPARE_IMM:
+ case OP_COMPARE_IMM:
+ if (ins->inst_imm == 0 && ins->next && ins->next->opcode == OP_LBEQ) {
+ ins->next->opcode = OP_ARM64_CBZX;
+ ins->next->sreg1 = ins->sreg1;
+ NULLIFY_INS (ins);
+ } else if (ins->inst_imm == 0 && ins->next && ins->next->opcode == OP_LBNE_UN) {
+ ins->next->opcode = OP_ARM64_CBNZX;
+ ins->next->sreg1 = ins->sreg1;
+ NULLIFY_INS (ins);
+ }
+ break;
+ case OP_FCOMPARE: {
+ gboolean swap = FALSE;
+ int reg;
+
+ if (!ins->next) {
+ /* Optimized away */
+ NULLIFY_INS (ins);
+ break;
+ }
+
+ /*
+ * FP compares with unordered operands set the flags
+ * to NZCV=0011, which matches some non-unordered compares
+ * as well, like LE, so have to swap the operands.
+ */
+ switch (ins->next->opcode) {
+ case OP_FBLT:
+ ins->next->opcode = OP_FBGT;
+ swap = TRUE;
+ break;
+ case OP_FBLE:
+ ins->next->opcode = OP_FBGE;
+ swap = TRUE;
+ break;
+ default:
+ break;
+ }
+ if (swap) {
+ reg = ins->sreg1;
+ ins->sreg1 = ins->sreg2;
+ ins->sreg2 = reg;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ last_ins = ins;
+ }
+ bb->last_ins = last_ins;
+ bb->max_vreg = cfg->next_vreg;
+}
+
+void
+mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
+{
+}
+
+static int
+opcode_to_armcond (int opcode)
+{
+ switch (opcode) {
+ case OP_IBEQ:
+ case OP_LBEQ:
+ case OP_FBEQ:
+ case OP_CEQ:
+ case OP_ICEQ:
+ case OP_LCEQ:
+ case OP_FCEQ:
+ case OP_RCEQ:
+ case OP_COND_EXC_IEQ:
+ case OP_COND_EXC_EQ:
+ return ARMCOND_EQ;
+ case OP_IBGE:
+ case OP_LBGE:
+ case OP_FBGE:
+ case OP_ICGE:
+ case OP_FCGE:
+ case OP_RCGE:
+ return ARMCOND_GE;
+ case OP_IBGT:
+ case OP_LBGT:
+ case OP_FBGT:
+ case OP_CGT:
+ case OP_ICGT:
+ case OP_LCGT:
+ case OP_FCGT:
+ case OP_RCGT:
+ case OP_COND_EXC_IGT:
+ case OP_COND_EXC_GT:
+ return ARMCOND_GT;
+ case OP_IBLE:
+ case OP_LBLE:
+ case OP_FBLE:
+ case OP_ICLE:
+ case OP_FCLE:
+ case OP_RCLE:
+ return ARMCOND_LE;
+ case OP_IBLT:
+ case OP_LBLT:
+ case OP_FBLT:
+ case OP_CLT:
+ case OP_ICLT:
+ case OP_LCLT:
+ case OP_COND_EXC_ILT:
+ case OP_COND_EXC_LT:
+ return ARMCOND_LT;
+ case OP_IBNE_UN:
+ case OP_LBNE_UN:
+ case OP_FBNE_UN:
+ case OP_ICNEQ:
+ case OP_FCNEQ:
+ case OP_RCNEQ:
+ case OP_COND_EXC_INE_UN:
+ case OP_COND_EXC_NE_UN:
+ return ARMCOND_NE;
+ case OP_IBGE_UN:
+ case OP_LBGE_UN:
+ case OP_FBGE_UN:
+ case OP_ICGE_UN:
+ case OP_COND_EXC_IGE_UN:
+ case OP_COND_EXC_GE_UN:
+ return ARMCOND_HS;
+ case OP_IBGT_UN:
+ case OP_LBGT_UN:
+ case OP_FBGT_UN:
+ case OP_CGT_UN:
+ case OP_ICGT_UN:
+ case OP_LCGT_UN:
+ case OP_FCGT_UN:
+ case OP_RCGT_UN:
+ case OP_COND_EXC_IGT_UN:
+ case OP_COND_EXC_GT_UN:
+ return ARMCOND_HI;
+ case OP_IBLE_UN:
+ case OP_LBLE_UN:
+ case OP_FBLE_UN:
+ case OP_ICLE_UN:
+ case OP_COND_EXC_ILE_UN:
+ case OP_COND_EXC_LE_UN:
+ return ARMCOND_LS;
+ case OP_IBLT_UN:
+ case OP_LBLT_UN:
+ case OP_FBLT_UN:
+ case OP_CLT_UN:
+ case OP_ICLT_UN:
+ case OP_LCLT_UN:
+ case OP_COND_EXC_ILT_UN:
+ case OP_COND_EXC_LT_UN:
+ return ARMCOND_LO;
+ /*
+ * FCMP sets the NZCV condition bits as follows:
+ * eq = 0110
+ * < = 1000
+ * > = 0010
+ * unordered = 0011
+ * ARMCOND_LT is N!=V, so it matches unordered too, so
+ * fclt and fclt_un need to be special cased.
+ */
+ case OP_FCLT:
+ case OP_RCLT:
+ /* N==1 */
+ return ARMCOND_MI;
+ case OP_FCLT_UN:
+ case OP_RCLT_UN:
+ return ARMCOND_LT;
+ case OP_COND_EXC_C:
+ case OP_COND_EXC_IC:
+ return ARMCOND_CS;
+ case OP_COND_EXC_OV:
+ case OP_COND_EXC_IOV:
+ return ARMCOND_VS;
+ case OP_COND_EXC_NC:
+ case OP_COND_EXC_INC:
+ return ARMCOND_CC;
+ case OP_COND_EXC_NO:
+ case OP_COND_EXC_INO:
+ return ARMCOND_VC;
+ default:
+ printf ("%s\n", mono_inst_name (opcode));
+ g_assert_not_reached ();
+ return -1;
+ }
+}
+
+/* This clobbers LR */
+static inline __attribute__((warn_unused_result)) guint8*
+emit_cond_exc (MonoCompile *cfg, guint8 *code, int opcode, const char *exc_name)
+{
+ int cond;
+
+ cond = opcode_to_armcond (opcode);
+ /* Capture PC */
+ arm_adrx (code, ARMREG_IP1, code);
+ mono_add_patch_info_rel (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, exc_name, MONO_R_ARM64_BCC);
+ arm_bcc (code, cond, 0);
+ return code;
+}
+
+static guint8*
+emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins)
+{
+ CallInfo *cinfo;
+ MonoCallInst *call;
+
+ call = (MonoCallInst*)ins;
+ cinfo = call->call_info;
+ g_assert (cinfo);
+ switch (cinfo->ret.storage) {
+ case ArgNone:
+ break;
+ case ArgInIReg:
+ /* LLVM compiled code might only set the bottom bits */
+ if (call->signature && mini_get_underlying_type (call->signature->ret)->type == MONO_TYPE_I4)
+ arm_sxtwx (code, call->inst.dreg, cinfo->ret.reg);
+ else if (call->inst.dreg != cinfo->ret.reg)
+ arm_movx (code, call->inst.dreg, cinfo->ret.reg);
+ break;
+ case ArgInFReg:
+ if (call->inst.dreg != cinfo->ret.reg)
+ arm_fmovd (code, call->inst.dreg, cinfo->ret.reg);
+ break;
+ case ArgInFRegR4:
+ if (cfg->r4fp)
+ arm_fmovs (code, call->inst.dreg, cinfo->ret.reg);
+ else
+ arm_fcvt_sd (code, call->inst.dreg, cinfo->ret.reg);
+ break;
+ case ArgVtypeInIRegs: {
+ MonoInst *loc = cfg->arch.vret_addr_loc;
+ int i;
+
+ /* Load the destination address */
+ g_assert (loc && loc->opcode == OP_REGOFFSET);
+ code = emit_ldrx (code, ARMREG_LR, loc->inst_basereg, loc->inst_offset);
+ for (i = 0; i < cinfo->ret.nregs; ++i)
+ arm_strx (code, cinfo->ret.reg + i, ARMREG_LR, i * 8);
+ break;
+ }
+ case ArgHFA: {
+ MonoInst *loc = cfg->arch.vret_addr_loc;
+ int i;
+
+ /* Load the destination address */
+ g_assert (loc && loc->opcode == OP_REGOFFSET);
+ code = emit_ldrx (code, ARMREG_LR, loc->inst_basereg, loc->inst_offset);
+ for (i = 0; i < cinfo->ret.nregs; ++i) {
+ if (cinfo->ret.esize == 4)
+ arm_strfpw (code, cinfo->ret.reg + i, ARMREG_LR, cinfo->ret.foffsets [i]);
+ else
+ arm_strfpx (code, cinfo->ret.reg + i, ARMREG_LR, cinfo->ret.foffsets [i]);
+ }
+ break;
+ }
+ case ArgVtypeByRef:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ return code;
+}
+
+/*
+ * emit_branch_island:
+ *
+ * Emit a branch island for the conditional branches from cfg->native_code + start_offset to code.
+ */
+static guint8*
+emit_branch_island (MonoCompile *cfg, guint8 *code, int start_offset)
+{
+ MonoJumpInfo *ji;
+ int offset, island_size;
+
+ /* Iterate over the patch infos added so far by this bb */
+ island_size = 0;
+ for (ji = cfg->patch_info; ji; ji = ji->next) {
+ if (ji->ip.i < start_offset)
+ /* The patch infos are in reverse order, so this means the end */
+ break;
+ if (ji->relocation == MONO_R_ARM64_BCC || ji->relocation == MONO_R_ARM64_CBZ)
+ island_size += 4;
+ }
+
+ if (island_size) {
+ offset = code - cfg->native_code;
+ if (offset > (cfg->code_size - island_size - 16)) {
+ cfg->code_size *= 2;
+ cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+ code = cfg->native_code + offset;
+ }
+
+ /* Branch over the island */
+ arm_b (code, code + 4 + island_size);
+
+ for (ji = cfg->patch_info; ji; ji = ji->next) {
+ if (ji->ip.i < start_offset)
+ break;
+ if (ji->relocation == MONO_R_ARM64_BCC || ji->relocation == MONO_R_ARM64_CBZ) {
+ /* Rewrite the cond branch so it branches to an uncoditional branch in the branch island */
+ arm_patch_rel (cfg->native_code + ji->ip.i, code, ji->relocation);
+ /* Rewrite the patch so it points to the unconditional branch */
+ ji->ip.i = code - cfg->native_code;
+ ji->relocation = MONO_R_ARM64_B;
+ arm_b (code, code);
+ }
+ }
+ }
+ return code;
+}
+
+void
+mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ MonoInst *ins;
+ MonoCallInst *call;
+ guint offset;
+ guint8 *code = cfg->native_code + cfg->code_len;
+ int start_offset, max_len, dreg, sreg1, sreg2;
+ mgreg_t imm;
+
+ if (cfg->verbose_level > 2)
+ g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
+
+ start_offset = code - cfg->native_code;
+
+ MONO_BB_FOR_EACH_INS (bb, ins) {
+ offset = code - cfg->native_code;
+
+ max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
+
+ if (offset > (cfg->code_size - max_len - 16)) {
+ cfg->code_size *= 2;
+ cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+ code = cfg->native_code + offset;
+ }
+
+ if (G_UNLIKELY (cfg->arch.cond_branch_islands && offset - start_offset > 4 * 0x1ffff)) {
+ /* Emit a branch island for large basic blocks */
+ code = emit_branch_island (cfg, code, start_offset);
+ offset = code - cfg->native_code;
+ start_offset = offset;
+ }
+
+ mono_debug_record_line_number (cfg, ins, offset);
+
+ dreg = ins->dreg;
+ sreg1 = ins->sreg1;
+ sreg2 = ins->sreg2;
+ imm = ins->inst_imm;
+
+ switch (ins->opcode) {
+ case OP_ICONST:
+ code = emit_imm (code, dreg, ins->inst_c0);
+ break;
+ case OP_I8CONST:
+ code = emit_imm64 (code, dreg, ins->inst_c0);
+ break;
+ case OP_MOVE:
+ if (dreg != sreg1)
+ arm_movx (code, dreg, sreg1);
+ break;
+ case OP_NOP:
+ case OP_RELAXED_NOP:
+ break;
+ case OP_JUMP_TABLE:
+ mono_add_patch_info_rel (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0, MONO_R_ARM64_IMM);
+ code = emit_imm64_template (code, dreg);
+ break;
+ case OP_BREAK:
+ /*
+ * gdb does not like encountering the hw breakpoint ins in the debugged code.
+ * So instead of emitting a trap, we emit a call a C function and place a
+ * breakpoint there.
+ */
+ code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_break");
+ break;
+ case OP_LOCALLOC: {
+ guint8 *buf [16];
+
+ arm_addx_imm (code, ARMREG_IP0, sreg1, (MONO_ARCH_FRAME_ALIGNMENT - 1));
+ // FIXME: andx_imm doesn't work yet
+ code = emit_imm (code, ARMREG_IP1, -MONO_ARCH_FRAME_ALIGNMENT);
+ arm_andx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
+ //arm_andx_imm (code, ARMREG_IP0, sreg1, - MONO_ARCH_FRAME_ALIGNMENT);
+ arm_movspx (code, ARMREG_IP1, ARMREG_SP);
+ arm_subx (code, ARMREG_IP1, ARMREG_IP1, ARMREG_IP0);
+ arm_movspx (code, ARMREG_SP, ARMREG_IP1);
+
+ /* Init */
+ /* ip1 = pointer, ip0 = end */
+ arm_addx (code, ARMREG_IP0, ARMREG_IP1, ARMREG_IP0);
+ buf [0] = code;
+ arm_cmpx (code, ARMREG_IP1, ARMREG_IP0);
+ buf [1] = code;
+ arm_bcc (code, ARMCOND_EQ, 0);
+ arm_stpx (code, ARMREG_RZR, ARMREG_RZR, ARMREG_IP1, 0);
+ arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 16);
+ arm_b (code, buf [0]);
+ arm_patch_rel (buf [1], code, MONO_R_ARM64_BCC);
+
+ arm_movspx (code, dreg, ARMREG_SP);
+ if (cfg->param_area)
+ code = emit_subx_sp_imm (code, cfg->param_area);
+ break;
+ }
+ case OP_LOCALLOC_IMM: {
+ int imm, offset;
+
+ imm = ALIGN_TO (ins->inst_imm, MONO_ARCH_FRAME_ALIGNMENT);
+ g_assert (arm_is_arith_imm (imm));
+ arm_subx_imm (code, ARMREG_SP, ARMREG_SP, imm);
+
+ /* Init */
+ g_assert (MONO_ARCH_FRAME_ALIGNMENT == 16);
+ offset = 0;
+ while (offset < imm) {
+ arm_stpx (code, ARMREG_RZR, ARMREG_RZR, ARMREG_SP, offset);
+ offset += 16;
+ }
+ arm_movspx (code, dreg, ARMREG_SP);
+ if (cfg->param_area)
+ code = emit_subx_sp_imm (code, cfg->param_area);
+ break;
+ }
+ case OP_AOTCONST:
+ code = emit_aotconst (cfg, code, dreg, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
+ break;
+ case OP_OBJC_GET_SELECTOR:
+ mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_OBJC_SELECTOR_REF, ins->inst_p0);
+ /* See arch_emit_objc_selector_ref () in aot-compiler.c */
+ arm_ldrx_lit (code, ins->dreg, 0);
+ arm_nop (code);
+ arm_nop (code);
+ break;
+ case OP_SEQ_POINT: {
+ MonoInst *info_var = cfg->arch.seq_point_info_var;
+
+ /*
+ * For AOT, we use one got slot per method, which will point to a
+ * SeqPointInfo structure, containing all the information required
+ * by the code below.
+ */
+ if (cfg->compile_aot) {
+ g_assert (info_var);
+ g_assert (info_var->opcode == OP_REGOFFSET);
+ }
+
+ if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
+ MonoInst *var = cfg->arch.ss_tramp_var;
+
+ g_assert (var);
+ g_assert (var->opcode == OP_REGOFFSET);
+ /* Load ss_tramp_var */
+ /* This is equal to &ss_trampoline */
+ arm_ldrx (code, ARMREG_IP1, var->inst_basereg, var->inst_offset);
+ /* Load the trampoline address */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_IP1, 0);
+ /* Call it if it is non-null */
+ arm_cbzx (code, ARMREG_IP1, code + 8);
+ arm_blrx (code, ARMREG_IP1);
+ }
+
+ mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+
+ if (cfg->compile_aot) {
+ guint32 offset = code - cfg->native_code;
+ guint32 val;
+
+ arm_ldrx (code, ARMREG_IP1, info_var->inst_basereg, info_var->inst_offset);
+ /* Add the offset */
+ val = ((offset / 4) * sizeof (guint8*)) + MONO_STRUCT_OFFSET (SeqPointInfo, bp_addrs);
+ /* Load the info->bp_addrs [offset], which is either 0 or the address of the bp trampoline */
+ code = emit_ldrx (code, ARMREG_IP1, ARMREG_IP1, val);
+ /* Skip the load if its 0 */
+ arm_cbzx (code, ARMREG_IP1, code + 8);
+ /* Call the breakpoint trampoline */
+ arm_blrx (code, ARMREG_IP1);
+ } else {
+ MonoInst *var = cfg->arch.bp_tramp_var;
+
+ g_assert (var);
+ g_assert (var->opcode == OP_REGOFFSET);
+ /* Load the address of the bp trampoline into IP0 */
+ arm_ldrx (code, ARMREG_IP0, var->inst_basereg, var->inst_offset);
+ /*
+ * A placeholder for a possible breakpoint inserted by
+ * mono_arch_set_breakpoint ().
+ */
+ arm_nop (code);
+ }
+ break;
+ }
+
+ /* BRANCH */
+ case OP_BR:
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb, MONO_R_ARM64_B);
+ arm_b (code, code);
+ break;
+ case OP_BR_REG:
+ arm_brx (code, sreg1);
+ break;
+ case OP_IBEQ:
+ case OP_IBGE:
+ case OP_IBGT:
+ case OP_IBLE:
+ case OP_IBLT:
+ case OP_IBNE_UN:
+ case OP_IBGE_UN:
+ case OP_IBGT_UN:
+ case OP_IBLE_UN:
+ case OP_IBLT_UN:
+ case OP_LBEQ:
+ case OP_LBGE:
+ case OP_LBGT:
+ case OP_LBLE:
+ case OP_LBLT:
+ case OP_LBNE_UN:
+ case OP_LBGE_UN:
+ case OP_LBGT_UN:
+ case OP_LBLE_UN:
+ case OP_LBLT_UN:
+ case OP_FBEQ:
+ case OP_FBNE_UN:
+ case OP_FBLT:
+ case OP_FBGT:
+ case OP_FBGT_UN:
+ case OP_FBLE:
+ case OP_FBGE:
+ case OP_FBGE_UN: {
+ int cond;
+
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_BCC);
+ cond = opcode_to_armcond (ins->opcode);
+ arm_bcc (code, cond, 0);
+ break;
+ }
+ case OP_FBLT_UN:
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_BCC);
+ /* For fp compares, ARMCOND_LT is lt or unordered */
+ arm_bcc (code, ARMCOND_LT, 0);
+ break;
+ case OP_FBLE_UN:
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_BCC);
+ arm_bcc (code, ARMCOND_EQ, 0);
+ offset = code - cfg->native_code;
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_BCC);
+ /* For fp compares, ARMCOND_LT is lt or unordered */
+ arm_bcc (code, ARMCOND_LT, 0);
+ break;
+ case OP_ARM64_CBZW:
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_CBZ);
+ arm_cbzw (code, sreg1, 0);
+ break;
+ case OP_ARM64_CBZX:
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_CBZ);
+ arm_cbzx (code, sreg1, 0);
+ break;
+ case OP_ARM64_CBNZW:
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_CBZ);
+ arm_cbnzw (code, sreg1, 0);
+ break;
+ case OP_ARM64_CBNZX:
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_CBZ);
+ arm_cbnzx (code, sreg1, 0);
+ break;
+ /* ALU */
+ case OP_IADD:
+ arm_addw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LADD:
+ arm_addx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_ISUB:
+ arm_subw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LSUB:
+ arm_subx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_IAND:
+ arm_andw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LAND:
+ arm_andx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_IOR:
+ arm_orrw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LOR:
+ arm_orrx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_IXOR:
+ arm_eorw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LXOR:
+ arm_eorx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_INEG:
+ arm_negw (code, dreg, sreg1);
+ break;
+ case OP_LNEG:
+ arm_negx (code, dreg, sreg1);
+ break;
+ case OP_INOT:
+ arm_mvnw (code, dreg, sreg1);
+ break;
+ case OP_LNOT:
+ arm_mvnx (code, dreg, sreg1);
+ break;
+ case OP_IADDCC:
+ arm_addsw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_ADDCC:
+ case OP_LADDCC:
+ arm_addsx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_ISUBCC:
+ arm_subsw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LSUBCC:
+ case OP_SUBCC:
+ arm_subsx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_ICOMPARE:
+ arm_cmpw (code, sreg1, sreg2);
+ break;
+ case OP_COMPARE:
+ case OP_LCOMPARE:
+ arm_cmpx (code, sreg1, sreg2);
+ break;
+ case OP_IADD_IMM:
+ code = emit_addw_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_LADD_IMM:
+ case OP_ADD_IMM:
+ code = emit_addx_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_ISUB_IMM:
+ code = emit_subw_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_LSUB_IMM:
+ code = emit_subx_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_IAND_IMM:
+ code = emit_andw_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_LAND_IMM:
+ case OP_AND_IMM:
+ code = emit_andx_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_IOR_IMM:
+ code = emit_orrw_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_LOR_IMM:
+ code = emit_orrx_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_IXOR_IMM:
+ code = emit_eorw_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_LXOR_IMM:
+ code = emit_eorx_imm (code, dreg, sreg1, imm);
+ break;
+ case OP_ICOMPARE_IMM:
+ code = emit_cmpw_imm (code, sreg1, imm);
+ break;
+ case OP_LCOMPARE_IMM:
+ case OP_COMPARE_IMM:
+ if (imm == 0) {
+ arm_cmpx (code, sreg1, ARMREG_RZR);
+ } else {
+ // FIXME: 32 vs 64 bit issues for 0xffffffff
+ code = emit_imm64 (code, ARMREG_LR, imm);
+ arm_cmpx (code, sreg1, ARMREG_LR);
+ }
+ break;
+ case OP_ISHL:
+ arm_lslvw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LSHL:
+ arm_lslvx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_ISHR:
+ arm_asrvw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LSHR:
+ arm_asrvx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_ISHR_UN:
+ arm_lsrvw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LSHR_UN:
+ arm_lsrvx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_ISHL_IMM:
+ if (imm == 0)
+ arm_movx (code, dreg, sreg1);
+ else
+ arm_lslw (code, dreg, sreg1, imm);
+ break;
+ case OP_LSHL_IMM:
+ if (imm == 0)
+ arm_movx (code, dreg, sreg1);
+ else
+ arm_lslx (code, dreg, sreg1, imm);
+ break;
+ case OP_ISHR_IMM:
+ if (imm == 0)
+ arm_movx (code, dreg, sreg1);
+ else
+ arm_asrw (code, dreg, sreg1, imm);
+ break;
+ case OP_LSHR_IMM:
+ case OP_SHR_IMM:
+ if (imm == 0)
+ arm_movx (code, dreg, sreg1);
+ else
+ arm_asrx (code, dreg, sreg1, imm);
+ break;
+ case OP_ISHR_UN_IMM:
+ if (imm == 0)
+ arm_movx (code, dreg, sreg1);
+ else
+ arm_lsrw (code, dreg, sreg1, imm);
+ break;
+ case OP_SHR_UN_IMM:
+ case OP_LSHR_UN_IMM:
+ if (imm == 0)
+ arm_movx (code, dreg, sreg1);
+ else
+ arm_lsrx (code, dreg, sreg1, imm);
+ break;
+
+ /* 64BIT ALU */
+ case OP_SEXT_I4:
+ arm_sxtwx (code, dreg, sreg1);
+ break;
+ case OP_ZEXT_I4:
+ /* Clean out the upper word */
+ arm_movw (code, dreg, sreg1);
+ break;
+ case OP_SHL_IMM:
+ arm_lslx (code, dreg, sreg1, imm);
+ break;
+
+ /* MULTIPLY/DIVISION */
+ case OP_IDIV:
+ case OP_IREM:
+ // FIXME: Optimize this
+ /* Check for zero */
+ arm_cmpx_imm (code, sreg2, 0);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
+ /* Check for INT_MIN/-1 */
+ code = emit_imm (code, ARMREG_IP0, 0x80000000);
+ arm_cmpx (code, sreg1, ARMREG_IP0);
+ arm_cset (code, ARMCOND_EQ, ARMREG_IP1);
+ code = emit_imm (code, ARMREG_IP0, 0xffffffff);
+ arm_cmpx (code, sreg2, ARMREG_IP0);
+ arm_cset (code, ARMCOND_EQ, ARMREG_IP0);
+ arm_andx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
+ arm_cmpx_imm (code, ARMREG_IP0, 1);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "OverflowException");
+ if (ins->opcode == OP_IREM) {
+ arm_sdivw (code, ARMREG_LR, sreg1, sreg2);
+ arm_msubw (code, dreg, ARMREG_LR, sreg2, sreg1);
+ } else {
+ arm_sdivw (code, dreg, sreg1, sreg2);
+ }
+ break;
+ case OP_IDIV_UN:
+ arm_cmpx_imm (code, sreg2, 0);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
+ arm_udivw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_IREM_UN:
+ arm_cmpx_imm (code, sreg2, 0);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
+ arm_udivw (code, ARMREG_LR, sreg1, sreg2);
+ arm_msubw (code, dreg, ARMREG_LR, sreg2, sreg1);
+ break;
+ case OP_LDIV:
+ case OP_LREM:
+ // FIXME: Optimize this
+ /* Check for zero */
+ arm_cmpx_imm (code, sreg2, 0);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
+ /* Check for INT64_MIN/-1 */
+ code = emit_imm64 (code, ARMREG_IP0, 0x8000000000000000);
+ arm_cmpx (code, sreg1, ARMREG_IP0);
+ arm_cset (code, ARMCOND_EQ, ARMREG_IP1);
+ code = emit_imm64 (code, ARMREG_IP0, 0xffffffffffffffff);
+ arm_cmpx (code, sreg2, ARMREG_IP0);
+ arm_cset (code, ARMCOND_EQ, ARMREG_IP0);
+ arm_andx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
+ arm_cmpx_imm (code, ARMREG_IP0, 1);
+ /* 64 bit uses ArithmeticException */
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "ArithmeticException");
+ if (ins->opcode == OP_LREM) {
+ arm_sdivx (code, ARMREG_LR, sreg1, sreg2);
+ arm_msubx (code, dreg, ARMREG_LR, sreg2, sreg1);
+ } else {
+ arm_sdivx (code, dreg, sreg1, sreg2);
+ }
+ break;
+ case OP_LDIV_UN:
+ arm_cmpx_imm (code, sreg2, 0);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
+ arm_udivx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LREM_UN:
+ arm_cmpx_imm (code, sreg2, 0);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
+ arm_udivx (code, ARMREG_LR, sreg1, sreg2);
+ arm_msubx (code, dreg, ARMREG_LR, sreg2, sreg1);
+ break;
+ case OP_IMUL:
+ arm_mulw (code, dreg, sreg1, sreg2);
+ break;
+ case OP_LMUL:
+ arm_mulx (code, dreg, sreg1, sreg2);
+ break;
+ case OP_IMUL_IMM:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_mulw (code, dreg, sreg1, ARMREG_LR);
+ break;
+ case OP_MUL_IMM:
+ case OP_LMUL_IMM:
+ code = emit_imm (code, ARMREG_LR, imm);
+ arm_mulx (code, dreg, sreg1, ARMREG_LR);
+ break;
+
+ /* CONVERSIONS */
+ case OP_ICONV_TO_I1:
+ case OP_LCONV_TO_I1:
+ arm_sxtbx (code, dreg, sreg1);
+ break;
+ case OP_ICONV_TO_I2:
+ case OP_LCONV_TO_I2:
+ arm_sxthx (code, dreg, sreg1);
+ break;
+ case OP_ICONV_TO_U1:
+ case OP_LCONV_TO_U1:
+ arm_uxtbw (code, dreg, sreg1);
+ break;
+ case OP_ICONV_TO_U2:
+ case OP_LCONV_TO_U2:
+ arm_uxthw (code, dreg, sreg1);
+ break;
+
+ /* CSET */
+ case OP_CEQ:
+ case OP_ICEQ:
+ case OP_LCEQ:
+ case OP_CLT:
+ case OP_ICLT:
+ case OP_LCLT:
+ case OP_CGT:
+ case OP_ICGT:
+ case OP_LCGT:
+ case OP_CLT_UN:
+ case OP_ICLT_UN:
+ case OP_LCLT_UN:
+ case OP_CGT_UN:
+ case OP_ICGT_UN:
+ case OP_LCGT_UN:
+ case OP_ICNEQ:
+ case OP_ICGE:
+ case OP_ICLE:
+ case OP_ICGE_UN:
+ case OP_ICLE_UN: {
+ int cond;
+
+ cond = opcode_to_armcond (ins->opcode);
+ arm_cset (code, cond, dreg);
+ break;
+ }
+ case OP_FCEQ:
+ case OP_FCLT:
+ case OP_FCLT_UN:
+ case OP_FCGT:
+ case OP_FCGT_UN:
+ case OP_FCNEQ:
+ case OP_FCLE:
+ case OP_FCGE: {
+ int cond;
+
+ cond = opcode_to_armcond (ins->opcode);
+ arm_fcmpd (code, sreg1, sreg2);
+ arm_cset (code, cond, dreg);
+ break;
+ }
+
+ /* MEMORY */
+ case OP_LOADI1_MEMBASE:
+ code = emit_ldrsbx (code, dreg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case OP_LOADU1_MEMBASE:
+ code = emit_ldrb (code, dreg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case OP_LOADI2_MEMBASE:
+ code = emit_ldrshx (code, dreg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case OP_LOADU2_MEMBASE:
+ code = emit_ldrh (code, dreg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case OP_LOADI4_MEMBASE:
+ code = emit_ldrswx (code, dreg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case OP_LOADU4_MEMBASE:
+ code = emit_ldrw (code, dreg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case OP_LOAD_MEMBASE:
+ case OP_LOADI8_MEMBASE:
+ code = emit_ldrx (code, dreg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case OP_STOREI1_MEMBASE_IMM:
+ case OP_STOREI2_MEMBASE_IMM:
+ case OP_STOREI4_MEMBASE_IMM:
+ case OP_STORE_MEMBASE_IMM:
+ case OP_STOREI8_MEMBASE_IMM: {
+ int immreg;
+
+ if (imm != 0) {
+ code = emit_imm (code, ARMREG_LR, imm);
+ immreg = ARMREG_LR;
+ } else {
+ immreg = ARMREG_RZR;
+ }
+
+ switch (ins->opcode) {
+ case OP_STOREI1_MEMBASE_IMM:
+ code = emit_strb (code, immreg, ins->inst_destbasereg, ins->inst_offset);
+ break;
+ case OP_STOREI2_MEMBASE_IMM:
+ code = emit_strh (code, immreg, ins->inst_destbasereg, ins->inst_offset);
+ break;
+ case OP_STOREI4_MEMBASE_IMM:
+ code = emit_strw (code, immreg, ins->inst_destbasereg, ins->inst_offset);
+ break;
+ case OP_STORE_MEMBASE_IMM:
+ case OP_STOREI8_MEMBASE_IMM:
+ code = emit_strx (code, immreg, ins->inst_destbasereg, ins->inst_offset);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+ }
+ case OP_STOREI1_MEMBASE_REG:
+ code = emit_strb (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
+ break;
+ case OP_STOREI2_MEMBASE_REG:
+ code = emit_strh (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
+ break;
+ case OP_STOREI4_MEMBASE_REG:
+ code = emit_strw (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
+ break;
+ case OP_STORE_MEMBASE_REG:
+ case OP_STOREI8_MEMBASE_REG:
+ code = emit_strx (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
+ break;
+
+ case OP_TLS_GET:
+ code = emit_tls_get (code, dreg, ins->inst_offset);
+ break;
+ case OP_TLS_GET_REG:
+ code = emit_tls_get_reg (code, dreg, sreg1);
+ break;
+ case OP_TLS_SET:
+ code = emit_tls_set (code, sreg1, ins->inst_offset);
+ break;
+ case OP_TLS_SET_REG:
+ code = emit_tls_set_reg (code, sreg1, sreg2);
+ break;
+
+ /* Atomic */
+ case OP_MEMORY_BARRIER:
+ arm_dmb (code, 0);
+ break;
+ case OP_ATOMIC_ADD_I4: {
+ guint8 *buf [16];
+
+ buf [0] = code;
+ arm_ldaxrw (code, ARMREG_IP0, sreg1);
+ arm_addx (code, ARMREG_IP0, ARMREG_IP0, sreg2);
+ arm_stlxrw (code, ARMREG_IP1, ARMREG_IP0, sreg1);
+ arm_cbnzw (code, ARMREG_IP1, buf [0]);
+
+ arm_movx (code, dreg, ARMREG_IP0);
+ break;
+ }
+ case OP_ATOMIC_ADD_I8: {
+ guint8 *buf [16];
+
+ buf [0] = code;
+ arm_ldaxrx (code, ARMREG_IP0, sreg1);
+ arm_addx (code, ARMREG_IP0, ARMREG_IP0, sreg2);
+ arm_stlxrx (code, ARMREG_IP1, ARMREG_IP0, sreg1);
+ arm_cbnzx (code, ARMREG_IP1, buf [0]);
+
+ arm_movx (code, dreg, ARMREG_IP0);
+ break;
+ }
+ case OP_ATOMIC_EXCHANGE_I4: {
+ guint8 *buf [16];
+
+ buf [0] = code;
+ arm_ldaxrw (code, ARMREG_IP0, sreg1);
+ arm_stlxrw (code, ARMREG_IP1, sreg2, sreg1);
+ arm_cbnzw (code, ARMREG_IP1, buf [0]);
+
+ arm_movx (code, dreg, ARMREG_IP0);
+ break;
+ }
+ case OP_ATOMIC_EXCHANGE_I8: {
+ guint8 *buf [16];
+
+ buf [0] = code;
+ arm_ldaxrx (code, ARMREG_IP0, sreg1);
+ arm_stlxrx (code, ARMREG_IP1, sreg2, sreg1);
+ arm_cbnzw (code, ARMREG_IP1, buf [0]);
+
+ arm_movx (code, dreg, ARMREG_IP0);
+ break;
+ }
+ case OP_ATOMIC_CAS_I4: {
+ guint8 *buf [16];
+
+ /* sreg2 is the value, sreg3 is the comparand */
+ buf [0] = code;
+ arm_ldaxrw (code, ARMREG_IP0, sreg1);
+ arm_cmpw (code, ARMREG_IP0, ins->sreg3);
+ buf [1] = code;
+ arm_bcc (code, ARMCOND_NE, 0);
+ arm_stlxrw (code, ARMREG_IP1, sreg2, sreg1);
+ arm_cbnzw (code, ARMREG_IP1, buf [0]);
+ arm_patch_rel (buf [1], code, MONO_R_ARM64_BCC);
+
+ arm_movx (code, dreg, ARMREG_IP0);
+ break;
+ }
+ case OP_ATOMIC_CAS_I8: {
+ guint8 *buf [16];
+
+ buf [0] = code;
+ arm_ldaxrx (code, ARMREG_IP0, sreg1);
+ arm_cmpx (code, ARMREG_IP0, ins->sreg3);
+ buf [1] = code;
+ arm_bcc (code, ARMCOND_NE, 0);
+ arm_stlxrx (code, ARMREG_IP1, sreg2, sreg1);
+ arm_cbnzw (code, ARMREG_IP1, buf [0]);
+ arm_patch_rel (buf [1], code, MONO_R_ARM64_BCC);
+
+ arm_movx (code, dreg, ARMREG_IP0);
+ break;
+ }
+ case OP_ATOMIC_LOAD_I1: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ arm_ldarb (code, ins->dreg, ARMREG_LR);
+ arm_sxtbx (code, ins->dreg, ins->dreg);
+ break;
+ }
+ case OP_ATOMIC_LOAD_U1: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ arm_ldarb (code, ins->dreg, ARMREG_LR);
+ arm_uxtbx (code, ins->dreg, ins->dreg);
+ break;
+ }
+ case OP_ATOMIC_LOAD_I2: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ arm_ldarh (code, ins->dreg, ARMREG_LR);
+ arm_sxthx (code, ins->dreg, ins->dreg);
+ break;
+ }
+ case OP_ATOMIC_LOAD_U2: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ arm_ldarh (code, ins->dreg, ARMREG_LR);
+ arm_uxthx (code, ins->dreg, ins->dreg);
+ break;
+ }
+ case OP_ATOMIC_LOAD_I4: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ arm_ldarw (code, ins->dreg, ARMREG_LR);
+ arm_sxtwx (code, ins->dreg, ins->dreg);
+ break;
+ }
+ case OP_ATOMIC_LOAD_U4: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ arm_ldarw (code, ins->dreg, ARMREG_LR);
+ arm_movw (code, ins->dreg, ins->dreg); /* Clear upper half of the register. */
+ break;
+ }
+ case OP_ATOMIC_LOAD_I8:
+ case OP_ATOMIC_LOAD_U8: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ arm_ldarx (code, ins->dreg, ARMREG_LR);
+ break;
+ }
+ case OP_ATOMIC_LOAD_R4: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ if (cfg->r4fp) {
+ arm_ldarw (code, ARMREG_LR, ARMREG_LR);
+ arm_fmov_rx_to_double (code, ins->dreg, ARMREG_LR);
+ } else {
+ arm_ldarw (code, ARMREG_LR, ARMREG_LR);
+ arm_fmov_rx_to_double (code, FP_TEMP_REG, ARMREG_LR);
+ arm_fcvt_sd (code, ins->dreg, FP_TEMP_REG);
+ }
+ break;
+ }
+ case OP_ATOMIC_LOAD_R8: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
+ arm_ldarx (code, ARMREG_LR, ARMREG_LR);
+ arm_fmov_rx_to_double (code, ins->dreg, ARMREG_LR);
+ break;
+ }
+ case OP_ATOMIC_STORE_I1:
+ case OP_ATOMIC_STORE_U1: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
+ arm_stlrb (code, ARMREG_LR, ins->sreg1);
+ break;
+ }
+ case OP_ATOMIC_STORE_I2:
+ case OP_ATOMIC_STORE_U2: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
+ arm_stlrh (code, ARMREG_LR, ins->sreg1);
+ break;
+ }
+ case OP_ATOMIC_STORE_I4:
+ case OP_ATOMIC_STORE_U4: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
+ arm_stlrw (code, ARMREG_LR, ins->sreg1);
+ break;
+ }
+ case OP_ATOMIC_STORE_I8:
+ case OP_ATOMIC_STORE_U8: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
+ arm_stlrx (code, ARMREG_LR, ins->sreg1);
+ break;
+ }
+ case OP_ATOMIC_STORE_R4: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
+ if (cfg->r4fp) {
+ arm_fmov_double_to_rx (code, ARMREG_IP0, ins->sreg1);
+ arm_stlrw (code, ARMREG_LR, ARMREG_IP0);
+ } else {
+ arm_fcvt_ds (code, FP_TEMP_REG, ins->sreg1);
+ arm_fmov_double_to_rx (code, ARMREG_IP0, FP_TEMP_REG);
+ arm_stlrw (code, ARMREG_LR, ARMREG_IP0);
+ }
+ break;
+ }
+ case OP_ATOMIC_STORE_R8: {
+ code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
+ arm_fmov_double_to_rx (code, ARMREG_IP0, ins->sreg1);
+ arm_stlrx (code, ARMREG_LR, ARMREG_IP0);
+ break;
+ }
+
+ /* FP */
+ case OP_R8CONST: {
+ guint64 imm = *(guint64*)ins->inst_p0;
+
+ if (imm == 0) {
+ arm_fmov_rx_to_double (code, dreg, ARMREG_RZR);
+ } else {
+ code = emit_imm64 (code, ARMREG_LR, imm);
+ arm_fmov_rx_to_double (code, ins->dreg, ARMREG_LR);
+ }
+ break;
+ }
+ case OP_R4CONST: {
+ guint64 imm = *(guint32*)ins->inst_p0;
+
+ code = emit_imm64 (code, ARMREG_LR, imm);
+ if (cfg->r4fp) {
+ arm_fmov_rx_to_double (code, dreg, ARMREG_LR);
+ } else {
+ arm_fmov_rx_to_double (code, FP_TEMP_REG, ARMREG_LR);
+ arm_fcvt_sd (code, dreg, FP_TEMP_REG);
+ }
+ break;
+ }
+ case OP_LOADR8_MEMBASE:
+ code = emit_ldrfpx (code, dreg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case OP_LOADR4_MEMBASE:
+ if (cfg->r4fp) {
+ code = emit_ldrfpw (code, dreg, ins->inst_basereg, ins->inst_offset);
+ } else {
+ code = emit_ldrfpw (code, FP_TEMP_REG, ins->inst_basereg, ins->inst_offset);
+ arm_fcvt_sd (code, dreg, FP_TEMP_REG);
+ }
+ break;
+ case OP_STORER8_MEMBASE_REG:
+ code = emit_strfpx (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
+ break;
+ case OP_STORER4_MEMBASE_REG:
+ if (cfg->r4fp) {
+ code = emit_strfpw (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
+ } else {
+ arm_fcvt_ds (code, FP_TEMP_REG, sreg1);
+ code = emit_strfpw (code, FP_TEMP_REG, ins->inst_destbasereg, ins->inst_offset);
+ }
+ break;
+ case OP_FMOVE:
+ if (dreg != sreg1)
+ arm_fmovd (code, dreg, sreg1);
+ break;
+ case OP_RMOVE:
+ if (dreg != sreg1)
+ arm_fmovs (code, dreg, sreg1);
+ break;
+ case OP_MOVE_F_TO_I4:
+ if (cfg->r4fp) {
+ arm_fmov_double_to_rx (code, ins->dreg, ins->sreg1);
+ } else {
+ arm_fcvt_ds (code, ins->dreg, ins->sreg1);
+ arm_fmov_double_to_rx (code, ins->dreg, ins->dreg);
+ }
+ break;
+ case OP_MOVE_I4_TO_F:
+ if (cfg->r4fp) {
+ arm_fmov_rx_to_double (code, ins->dreg, ins->sreg1);
+ } else {
+ arm_fmov_rx_to_double (code, ins->dreg, ins->sreg1);
+ arm_fcvt_sd (code, ins->dreg, ins->dreg);
+ }
+ break;
+ case OP_MOVE_F_TO_I8:
+ arm_fmov_double_to_rx (code, ins->dreg, ins->sreg1);
+ break;
+ case OP_MOVE_I8_TO_F:
+ arm_fmov_rx_to_double (code, ins->dreg, ins->sreg1);
+ break;
+ case OP_FCOMPARE:
+ arm_fcmpd (code, sreg1, sreg2);
+ break;
+ case OP_RCOMPARE:
+ arm_fcmps (code, sreg1, sreg2);
+ break;
+ case OP_FCONV_TO_I1:
+ arm_fcvtzs_dx (code, dreg, sreg1);
+ arm_sxtbx (code, dreg, dreg);
+ break;
+ case OP_FCONV_TO_U1:
+ arm_fcvtzu_dx (code, dreg, sreg1);
+ arm_uxtbw (code, dreg, dreg);
+ break;
+ case OP_FCONV_TO_I2:
+ arm_fcvtzs_dx (code, dreg, sreg1);
+ arm_sxthx (code, dreg, dreg);
+ break;
+ case OP_FCONV_TO_U2:
+ arm_fcvtzu_dx (code, dreg, sreg1);
+ arm_uxthw (code, dreg, dreg);
+ break;
+ case OP_FCONV_TO_I4:
+ arm_fcvtzs_dx (code, dreg, sreg1);
+ arm_sxtwx (code, dreg, dreg);
+ break;
+ case OP_FCONV_TO_U4:
+ arm_fcvtzu_dx (code, dreg, sreg1);
+ break;
+ case OP_FCONV_TO_I8:
+ arm_fcvtzs_dx (code, dreg, sreg1);
+ break;
+ case OP_FCONV_TO_U8:
+ arm_fcvtzu_dx (code, dreg, sreg1);
+ break;
+ case OP_FCONV_TO_R4:
+ if (cfg->r4fp) {
+ arm_fcvt_ds (code, dreg, sreg1);
+ } else {
+ arm_fcvt_ds (code, FP_TEMP_REG, sreg1);
+ arm_fcvt_sd (code, dreg, FP_TEMP_REG);
+ }
+ break;
+ case OP_ICONV_TO_R4:
+ if (cfg->r4fp) {
+ arm_scvtf_rw_to_s (code, dreg, sreg1);
+ } else {
+ arm_scvtf_rw_to_s (code, FP_TEMP_REG, sreg1);
+ arm_fcvt_sd (code, dreg, FP_TEMP_REG);
+ }
+ break;
+ case OP_LCONV_TO_R4:
+ if (cfg->r4fp) {
+ arm_scvtf_rx_to_s (code, dreg, sreg1);
+ } else {
+ arm_scvtf_rx_to_s (code, FP_TEMP_REG, sreg1);
+ arm_fcvt_sd (code, dreg, FP_TEMP_REG);
+ }
+ break;
+ case OP_ICONV_TO_R8:
+ arm_scvtf_rw_to_d (code, dreg, sreg1);
+ break;
+ case OP_LCONV_TO_R8:
+ arm_scvtf_rx_to_d (code, dreg, sreg1);
+ break;
+ case OP_ICONV_TO_R_UN:
+ arm_ucvtf_rw_to_d (code, dreg, sreg1);
+ break;
+ case OP_LCONV_TO_R_UN:
+ arm_ucvtf_rx_to_d (code, dreg, sreg1);
+ break;
+ case OP_FADD:
+ arm_fadd_d (code, dreg, sreg1, sreg2);
+ break;
+ case OP_FSUB:
+ arm_fsub_d (code, dreg, sreg1, sreg2);
+ break;
+ case OP_FMUL:
+ arm_fmul_d (code, dreg, sreg1, sreg2);
+ break;
+ case OP_FDIV:
+ arm_fdiv_d (code, dreg, sreg1, sreg2);
+ break;
+ case OP_FREM:
+ /* Emulated */
+ g_assert_not_reached ();
+ break;
+ case OP_FNEG:
+ arm_fneg_d (code, dreg, sreg1);
+ break;
+ case OP_ARM_SETFREG_R4:
+ arm_fcvt_ds (code, dreg, sreg1);
+ break;
+ case OP_CKFINITE:
+ /* Check for infinity */
+ code = emit_imm64 (code, ARMREG_LR, 0x7fefffffffffffffLL);
+ arm_fmov_rx_to_double (code, FP_TEMP_REG, ARMREG_LR);
+ arm_fabs_d (code, FP_TEMP_REG2, sreg1);
+ arm_fcmpd (code, FP_TEMP_REG2, FP_TEMP_REG);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_GT, "ArithmeticException");
+ /* Check for nans */
+ arm_fcmpd (code, FP_TEMP_REG2, FP_TEMP_REG2);
+ code = emit_cond_exc (cfg, code, OP_COND_EXC_OV, "ArithmeticException");
+ arm_fmovd (code, dreg, sreg1);
+ break;
+
+ /* R4 */
+ case OP_RADD:
+ arm_fadd_s (code, dreg, sreg1, sreg2);
+ break;
+ case OP_RSUB:
+ arm_fsub_s (code, dreg, sreg1, sreg2);
+ break;
+ case OP_RMUL:
+ arm_fmul_s (code, dreg, sreg1, sreg2);
+ break;
+ case OP_RDIV:
+ arm_fdiv_s (code, dreg, sreg1, sreg2);
+ break;
+ case OP_RNEG:
+ arm_fneg_s (code, dreg, sreg1);
+ break;
+ case OP_RCONV_TO_I1:
+ arm_fcvtzs_sx (code, dreg, sreg1);
+ arm_sxtbx (code, dreg, dreg);
+ break;
+ case OP_RCONV_TO_U1:
+ arm_fcvtzu_sx (code, dreg, sreg1);
+ arm_uxtbw (code, dreg, dreg);
+ break;
+ case OP_RCONV_TO_I2:
+ arm_fcvtzs_sx (code, dreg, sreg1);
+ arm_sxthx (code, dreg, dreg);
+ break;
+ case OP_RCONV_TO_U2:
+ arm_fcvtzu_sx (code, dreg, sreg1);
+ arm_uxthw (code, dreg, dreg);
+ break;
+ case OP_RCONV_TO_I4:
+ arm_fcvtzs_sx (code, dreg, sreg1);
+ arm_sxtwx (code, dreg, dreg);
+ break;
+ case OP_RCONV_TO_U4:
+ arm_fcvtzu_sx (code, dreg, sreg1);
+ break;
+ case OP_RCONV_TO_I8:
+ arm_fcvtzs_sx (code, dreg, sreg1);
+ break;
+ case OP_RCONV_TO_U8:
+ arm_fcvtzu_sx (code, dreg, sreg1);
+ break;
+ case OP_RCONV_TO_R8:
+ arm_fcvt_sd (code, dreg, sreg1);
+ break;
+ case OP_RCONV_TO_R4:
+ if (dreg != sreg1)
+ arm_fmovs (code, dreg, sreg1);
+ break;
+ case OP_RCEQ:
+ case OP_RCLT:
+ case OP_RCLT_UN:
+ case OP_RCGT:
+ case OP_RCGT_UN:
+ case OP_RCNEQ:
+ case OP_RCLE:
+ case OP_RCGE: {
+ int cond;
+
+ cond = opcode_to_armcond (ins->opcode);
+ arm_fcmps (code, sreg1, sreg2);
+ arm_cset (code, cond, dreg);
+ break;
+ }
+
+ /* CALLS */
+ case OP_VOIDCALL:
+ case OP_CALL:
+ case OP_LCALL:
+ case OP_FCALL:
+ case OP_RCALL:
+ case OP_VCALL2:
+ call = (MonoCallInst*)ins;
+ if (ins->flags & MONO_INST_HAS_METHOD)
+ code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
+ else
+ code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
+ code = emit_move_return_value (cfg, code, ins);
+ break;
+ case OP_VOIDCALL_REG:
+ case OP_CALL_REG:
+ case OP_LCALL_REG:
+ case OP_FCALL_REG:
+ case OP_RCALL_REG:
+ case OP_VCALL2_REG:
+ arm_blrx (code, sreg1);
+ code = emit_move_return_value (cfg, code, ins);
+ break;
+ case OP_VOIDCALL_MEMBASE:
+ case OP_CALL_MEMBASE:
+ case OP_LCALL_MEMBASE:
+ case OP_FCALL_MEMBASE:
+ case OP_RCALL_MEMBASE:
+ case OP_VCALL2_MEMBASE:
+ code = emit_ldrx (code, ARMREG_IP0, ins->inst_basereg, ins->inst_offset);
+ arm_blrx (code, ARMREG_IP0);
+ code = emit_move_return_value (cfg, code, ins);
+ break;
+ case OP_TAILCALL: {
+ MonoCallInst *call = (MonoCallInst*)ins;
+
+ g_assert (!cfg->method->save_lmf);
+
+ // FIXME: Copy stack arguments
+
+ /* Restore registers */
+ code = emit_load_regset (code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, cfg->arch.saved_gregs_offset);
+
+ /* Destroy frame */
+ code = mono_arm_emit_destroy_frame (code, cfg->stack_offset, ((1 << ARMREG_IP0) | (1 << ARMREG_IP1)));
+
+ if (cfg->compile_aot) {
+ /* This is not a PLT patch */
+ code = emit_aotconst (cfg, code, ARMREG_IP0, MONO_PATCH_INFO_METHOD_JUMP, call->method);
+ arm_brx (code, ARMREG_IP0);
+ } else {
+ mono_add_patch_info_rel (cfg, code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method, MONO_R_ARM64_B);
+ arm_b (code, code);
+ }
+ ins->flags |= MONO_INST_GC_CALLSITE;
+ ins->backend.pc_offset = code - cfg->native_code;
+ break;
+ }
+ case OP_ARGLIST:
+ g_assert (cfg->arch.cinfo);
+ code = emit_addx_imm (code, ARMREG_IP0, cfg->arch.args_reg, ((CallInfo*)cfg->arch.cinfo)->sig_cookie.offset);
+ arm_strx (code, ARMREG_IP0, sreg1, 0);
+ break;
+ case OP_DYN_CALL: {
+ MonoInst *var = cfg->dyn_call_var;
+ guint8 *labels [16];
+ int i;
+
+ /*
+ * sreg1 points to a DynCallArgs structure initialized by mono_arch_start_dyn_call ().
+ * sreg2 is the function to call.
+ */
+
+ g_assert (var->opcode == OP_REGOFFSET);
+
+ arm_movx (code, ARMREG_LR, sreg1);
+ arm_movx (code, ARMREG_IP1, sreg2);
+
+ /* Save args buffer */
+ code = emit_strx (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
+
+ /* Set fp argument regs */
+ code = emit_ldrw (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_fpargs));
+ arm_cmpw (code, ARMREG_R0, ARMREG_RZR);
+ labels [0] = code;
+ arm_bcc (code, ARMCOND_EQ, 0);
+ for (i = 0; i < 8; ++i)
+ code = emit_ldrfpx (code, ARMREG_D0 + i, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, fpregs) + (i * 8));
+ arm_patch_rel (labels [0], code, MONO_R_ARM64_BCC);
+
+ /* Set stack args */
+ for (i = 0; i < DYN_CALL_STACK_ARGS; ++i) {
+ code = emit_ldrx (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS + 1 + i) * sizeof (mgreg_t)));
+ code = emit_strx (code, ARMREG_R0, ARMREG_SP, i * sizeof (mgreg_t));
+ }
+
+ /* Set argument registers + r8 */
+ code = mono_arm_emit_load_regarray (code, 0x1ff, ARMREG_LR, 0);
+
+ /* Make the call */
+ arm_blrx (code, ARMREG_IP1);
+
+ /* Save result */
+ code = emit_ldrx (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
+ arm_strx (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, res));
+ arm_strx (code, ARMREG_R1, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, res2));
+ /* Save fp result */
+ code = emit_ldrw (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_fpret));
+ arm_cmpw (code, ARMREG_R0, ARMREG_RZR);
+ labels [1] = code;
+ arm_bcc (code, ARMCOND_EQ, 0);
+ for (i = 0; i < 8; ++i)
+ code = emit_strfpx (code, ARMREG_D0 + i, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, fpregs) + (i * 8));
+ arm_patch_rel (labels [1], code, MONO_R_ARM64_BCC);
+ break;
+ }
+
+ case OP_GENERIC_CLASS_INIT: {
+ static int byte_offset = -1;
+ static guint8 bitmask;
+ guint8 *jump;
+
+ if (byte_offset < 0)
+ mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
+
+ /* Load vtable->initialized */
+ arm_ldrsbx (code, ARMREG_IP0, sreg1, byte_offset);
+ // FIXME: No andx_imm yet */
+ code = mono_arm_emit_imm64 (code, ARMREG_IP1, bitmask);
+ arm_andx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
+ jump = code;
+ arm_cbnzx (code, ARMREG_IP0, 0);
+
+ /* Slowpath */
+ g_assert (sreg1 == ARMREG_R0);
+ code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ (gpointer)"mono_generic_class_init");
+
+ mono_arm_patch (jump, code, MONO_R_ARM64_CBZ);
+ break;
+ }
+
+ case OP_CHECK_THIS:
+ arm_ldrx (code, ARMREG_LR, sreg1, 0);
+ break;
+ case OP_NOT_NULL:
+ case OP_NOT_REACHED:
+ case OP_DUMMY_USE:
+ break;
+ case OP_IL_SEQ_POINT:
+ mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+ break;
+
+ /* EH */
+ case OP_COND_EXC_C:
+ case OP_COND_EXC_IC:
+ case OP_COND_EXC_OV:
+ case OP_COND_EXC_IOV:
+ case OP_COND_EXC_NC:
+ case OP_COND_EXC_INC:
+ case OP_COND_EXC_NO:
+ case OP_COND_EXC_INO:
+ case OP_COND_EXC_EQ:
+ case OP_COND_EXC_IEQ:
+ case OP_COND_EXC_NE_UN:
+ case OP_COND_EXC_INE_UN:
+ case OP_COND_EXC_ILT:
+ case OP_COND_EXC_LT:
+ case OP_COND_EXC_ILT_UN:
+ case OP_COND_EXC_LT_UN:
+ case OP_COND_EXC_IGT:
+ case OP_COND_EXC_GT:
+ case OP_COND_EXC_IGT_UN:
+ case OP_COND_EXC_GT_UN:
+ case OP_COND_EXC_IGE:
+ case OP_COND_EXC_GE:
+ case OP_COND_EXC_IGE_UN:
+ case OP_COND_EXC_GE_UN:
+ case OP_COND_EXC_ILE:
+ case OP_COND_EXC_LE:
+ case OP_COND_EXC_ILE_UN:
+ case OP_COND_EXC_LE_UN:
+ code = emit_cond_exc (cfg, code, ins->opcode, ins->inst_p1);
+ break;
+ case OP_THROW:
+ if (sreg1 != ARMREG_R0)
+ arm_movx (code, ARMREG_R0, sreg1);
+ code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ (gpointer)"mono_arch_throw_exception");
+ break;
+ case OP_RETHROW:
+ if (sreg1 != ARMREG_R0)
+ arm_movx (code, ARMREG_R0, sreg1);
+ code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ (gpointer)"mono_arch_rethrow_exception");
+ break;
+ case OP_CALL_HANDLER:
+ mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb, MONO_R_ARM64_BL);
+ arm_bl (code, 0);
+ cfg->thunk_area += THUNK_SIZE;
+ break;
+ case OP_START_HANDLER: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+
+ /* Save caller address */
+ code = emit_strx (code, ARMREG_LR, spvar->inst_basereg, spvar->inst_offset);
+
+ /*
+ * Reserve a param area, see test_0_finally_param_area ().
+ * This is needed because the param area is not set up when
+ * we are called from EH code.
+ */
+ if (cfg->param_area)
+ code = emit_subx_sp_imm (code, cfg->param_area);
+ break;
+ }
+ case OP_ENDFINALLY:
+ case OP_ENDFILTER: {
+ MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
+
+ if (cfg->param_area)
+ code = emit_addx_sp_imm (code, cfg->param_area);
+
+ if (ins->opcode == OP_ENDFILTER && sreg1 != ARMREG_R0)
+ arm_movx (code, ARMREG_R0, sreg1);
+
+ /* Return to either after the branch in OP_CALL_HANDLER, or to the EH code */
+ code = emit_ldrx (code, ARMREG_LR, spvar->inst_basereg, spvar->inst_offset);
+ arm_brx (code, ARMREG_LR);
+ break;
+ }
+ case OP_GET_EX_OBJ:
+ if (ins->dreg != ARMREG_R0)
+ arm_movx (code, ins->dreg, ARMREG_R0);
+ break;
+ case OP_GC_SAFE_POINT: {
+#if defined (USE_COOP_GC)
+ guint8 *buf [1];
+
+ arm_ldrx (code, ARMREG_IP1, ins->sreg1, 0);
+ /* Call it if it is non-null */
+ buf [0] = code;
+ arm_cbzx (code, ARMREG_IP1, 0);
+ code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_threads_state_poll");
+ mono_arm_patch (buf [0], code, MONO_R_ARM64_CBZ);
+#endif
+ break;
+ }
+
+ default:
+ g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
+ g_assert_not_reached ();
+ }
+
+ if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
+ g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
+ mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
+ g_assert_not_reached ();
+ }
+ }
+
+ /*
+ * If the compiled code size is larger than the bcc displacement (19 bits signed),
+ * insert branch islands between/inside basic blocks.
+ */
+ if (cfg->arch.cond_branch_islands)
+ code = emit_branch_island (cfg, code, start_offset);
+
+ cfg->code_len = code - cfg->native_code;
+}
+
+static guint8*
+emit_move_args (MonoCompile *cfg, guint8 *code)
+{
+ MonoInst *ins;
+ CallInfo *cinfo;
+ ArgInfo *ainfo;
+ int i, part;
+
+ cinfo = cfg->arch.cinfo;
+ g_assert (cinfo);
+ for (i = 0; i < cinfo->nargs; ++i) {
+ ainfo = cinfo->args + i;
+ ins = cfg->args [i];
+
+ if (ins->opcode == OP_REGVAR) {
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ arm_movx (code, ins->dreg, ainfo->reg);
+ break;
+ case ArgOnStack:
+ switch (ainfo->slot_size) {
+ case 1:
+ if (ainfo->sign)
+ code = emit_ldrsbx (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
+ else
+ code = emit_ldrb (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
+ break;
+ case 2:
+ if (ainfo->sign)
+ code = emit_ldrshx (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
+ else
+ code = emit_ldrh (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
+ break;
+ case 4:
+ if (ainfo->sign)
+ code = emit_ldrswx (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
+ else
+ code = emit_ldrw (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
+ break;
+ default:
+ code = emit_ldrx (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
+ break;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ } else {
+ if (ainfo->storage != ArgVtypeByRef && ainfo->storage != ArgVtypeByRefOnStack)
+ g_assert (ins->opcode == OP_REGOFFSET);
+
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ /* Stack slots for arguments have size 8 */
+ code = emit_strx (code, ainfo->reg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case ArgInFReg:
+ code = emit_strfpx (code, ainfo->reg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case ArgInFRegR4:
+ code = emit_strfpw (code, ainfo->reg, ins->inst_basereg, ins->inst_offset);
+ break;
+ case ArgOnStack:
+ case ArgOnStackR4:
+ case ArgOnStackR8:
+ case ArgVtypeByRefOnStack:
+ case ArgVtypeOnStack:
+ break;
+ case ArgVtypeByRef: {
+ MonoInst *addr_arg = ins->inst_left;
+
+ if (ainfo->gsharedvt) {
+ g_assert (ins->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
+ arm_strx (code, ainfo->reg, ins->inst_basereg, ins->inst_offset);
+ } else {
+ g_assert (ins->opcode == OP_VTARG_ADDR);
+ g_assert (addr_arg->opcode == OP_REGOFFSET);
+ arm_strx (code, ainfo->reg, addr_arg->inst_basereg, addr_arg->inst_offset);
+ }
+ break;
+ }
+ case ArgVtypeInIRegs:
+ for (part = 0; part < ainfo->nregs; part ++) {
+ code = emit_strx (code, ainfo->reg + part, ins->inst_basereg, ins->inst_offset + (part * 8));
+ }
+ break;
+ case ArgHFA:
+ for (part = 0; part < ainfo->nregs; part ++) {
+ if (ainfo->esize == 4)
+ code = emit_strfpw (code, ainfo->reg + part, ins->inst_basereg, ins->inst_offset + ainfo->foffsets [part]);
+ else
+ code = emit_strfpx (code, ainfo->reg + part, ins->inst_basereg, ins->inst_offset + ainfo->foffsets [part]);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ }
+
+ return code;
+}
+
+/*
+ * emit_store_regarray:
+ *
+ * Emit code to store the registers in REGS into the appropriate elements of
+ * the register array at BASEREG+OFFSET.
+ */
+static __attribute__((warn_unused_result)) guint8*
+emit_store_regarray (guint8 *code, guint64 regs, int basereg, int offset)
+{
+ int i;
+
+ for (i = 0; i < 32; ++i) {
+ if (regs & (1 << i)) {
+ if (i + 1 < 32 && (regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
+ arm_stpx (code, i, i + 1, basereg, offset + (i * 8));
+ i++;
+ } else if (i == ARMREG_SP) {
+ arm_movspx (code, ARMREG_IP1, ARMREG_SP);
+ arm_strx (code, ARMREG_IP1, basereg, offset + (i * 8));
+ } else {
+ arm_strx (code, i, basereg, offset + (i * 8));
+ }
+ }
+ }
+ return code;
+}
+
+/*
+ * emit_load_regarray:
+ *
+ * Emit code to load the registers in REGS from the appropriate elements of
+ * the register array at BASEREG+OFFSET.
+ */
+static __attribute__((warn_unused_result)) guint8*
+emit_load_regarray (guint8 *code, guint64 regs, int basereg, int offset)
+{
+ int i;
+
+ for (i = 0; i < 32; ++i) {
+ if (regs & (1 << i)) {
+ if ((regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
+ if (offset + (i * 8) < 500)
+ arm_ldpx (code, i, i + 1, basereg, offset + (i * 8));
+ else {
+ code = emit_ldrx (code, i, basereg, offset + (i * 8));
+ code = emit_ldrx (code, i + 1, basereg, offset + ((i + 1) * 8));
+ }
+ i++;
+ } else if (i == ARMREG_SP) {
+ g_assert_not_reached ();
+ } else {
+ code = emit_ldrx (code, i, basereg, offset + (i * 8));
+ }
+ }
+ }
+ return code;
+}
+
+/*
+ * emit_store_regset:
+ *
+ * Emit code to store the registers in REGS into consecutive memory locations starting
+ * at BASEREG+OFFSET.
+ */
+static __attribute__((warn_unused_result)) guint8*
+emit_store_regset (guint8 *code, guint64 regs, int basereg, int offset)
+{
+ int i, pos;
+
+ pos = 0;
+ for (i = 0; i < 32; ++i) {
+ if (regs & (1 << i)) {
+ if ((regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
+ arm_stpx (code, i, i + 1, basereg, offset + (pos * 8));
+ i++;
+ pos++;
+ } else if (i == ARMREG_SP) {
+ arm_movspx (code, ARMREG_IP1, ARMREG_SP);
+ arm_strx (code, ARMREG_IP1, basereg, offset + (pos * 8));
+ } else {
+ arm_strx (code, i, basereg, offset + (pos * 8));
+ }
+ pos++;
+ }
+ }
+ return code;
+}
+
+/*
+ * emit_load_regset:
+ *
+ * Emit code to load the registers in REGS from consecutive memory locations starting
+ * at BASEREG+OFFSET.
+ */
+static __attribute__((warn_unused_result)) guint8*
+emit_load_regset (guint8 *code, guint64 regs, int basereg, int offset)
+{
+ int i, pos;
+
+ pos = 0;
+ for (i = 0; i < 32; ++i) {
+ if (regs & (1 << i)) {
+ if ((regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
+ arm_ldpx (code, i, i + 1, basereg, offset + (pos * 8));
+ i++;
+ pos++;
+ } else if (i == ARMREG_SP) {
+ g_assert_not_reached ();
+ } else {
+ arm_ldrx (code, i, basereg, offset + (pos * 8));
+ }
+ pos++;
+ }
+ }
+ return code;
+}
+
+__attribute__((warn_unused_result)) guint8*
+mono_arm_emit_load_regarray (guint8 *code, guint64 regs, int basereg, int offset)
+{
+ return emit_load_regarray (code, regs, basereg, offset);
+}
+
+__attribute__((warn_unused_result)) guint8*
+mono_arm_emit_store_regarray (guint8 *code, guint64 regs, int basereg, int offset)
+{
+ return emit_store_regarray (code, regs, basereg, offset);
+}
+
+__attribute__((warn_unused_result)) guint8*
+mono_arm_emit_store_regset (guint8 *code, guint64 regs, int basereg, int offset)
+{
+ return emit_store_regset (code, regs, basereg, offset);
+}
+
+/* Same as emit_store_regset, but emit unwind info too */
+/* CFA_OFFSET is the offset between the CFA and basereg */
+static __attribute__((warn_unused_result)) guint8*
+emit_store_regset_cfa (MonoCompile *cfg, guint8 *code, guint64 regs, int basereg, int offset, int cfa_offset, guint64 no_cfa_regset)
+{
+ int i, j, pos, nregs;
+ guint32 cfa_regset = regs & ~no_cfa_regset;
+
+ pos = 0;
+ for (i = 0; i < 32; ++i) {
+ nregs = 1;
+ if (regs & (1 << i)) {
+ if ((regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
+ if (offset < 256) {
+ arm_stpx (code, i, i + 1, basereg, offset + (pos * 8));
+ } else {
+ code = emit_strx (code, i, basereg, offset + (pos * 8));
+ code = emit_strx (code, i + 1, basereg, offset + (pos * 8) + 8);
+ }
+ nregs = 2;
+ } else if (i == ARMREG_SP) {
+ arm_movspx (code, ARMREG_IP1, ARMREG_SP);
+ code = emit_strx (code, ARMREG_IP1, basereg, offset + (pos * 8));
+ } else {
+ code = emit_strx (code, i, basereg, offset + (pos * 8));
+ }
+
+ for (j = 0; j < nregs; ++j) {
+ if (cfa_regset & (1 << (i + j)))
+ mono_emit_unwind_op_offset (cfg, code, i + j, (- cfa_offset) + offset + ((pos + j) * 8));
+ }
+
+ i += nregs - 1;
+ pos += nregs;
+ }
+ }
+ return code;
+}
+
+/*
+ * emit_setup_lmf:
+ *
+ * Emit code to initialize an LMF structure at LMF_OFFSET.
+ * Clobbers ip0/ip1.
+ */
+static guint8*
+emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offset)
+{
+ /*
+ * The LMF should contain all the state required to be able to reconstruct the machine state
+ * at the current point of execution. Since the LMF is only read during EH, only callee
+ * saved etc. registers need to be saved.
+ * FIXME: Save callee saved fp regs, JITted code doesn't use them, but native code does, and they
+ * need to be restored during EH.
+ */
+
+ /* pc */
+ arm_adrx (code, ARMREG_LR, code);
+ code = emit_strx (code, ARMREG_LR, ARMREG_FP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, pc));
+ /* gregs + fp + sp */
+ /* Don't emit unwind info for sp/fp, they are already handled in the prolog */
+ code = emit_store_regset_cfa (cfg, code, MONO_ARCH_LMF_REGS, ARMREG_FP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs), cfa_offset, (1 << ARMREG_FP) | (1 << ARMREG_SP));
+
+ return code;
+}
+
+guint8 *
+mono_arch_emit_prolog (MonoCompile *cfg)
+{
+ MonoMethod *method = cfg->method;
+ MonoMethodSignature *sig;
+ MonoBasicBlock *bb;
+ guint8 *code;
+ int cfa_offset, max_offset;
+
+ sig = mono_method_signature (method);
+ cfg->code_size = 256 + sig->param_count * 64;
+ code = cfg->native_code = g_malloc (cfg->code_size);
+
+ /* This can be unaligned */
+ cfg->stack_offset = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
+
+ /*
+ * - Setup frame
+ */
+ cfa_offset = 0;
+ mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, 0);
+
+ /* Setup frame */
+ if (arm_is_ldpx_imm (-cfg->stack_offset)) {
+ arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -cfg->stack_offset);
+ } else {
+ /* sp -= cfg->stack_offset */
+ /* This clobbers ip0/ip1 */
+ code = emit_subx_sp_imm (code, cfg->stack_offset);
+ arm_stpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0);
+ }
+ cfa_offset += cfg->stack_offset;
+ mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
+ mono_emit_unwind_op_offset (cfg, code, ARMREG_FP, (- cfa_offset) + 0);
+ mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, (- cfa_offset) + 8);
+ arm_movspx (code, ARMREG_FP, ARMREG_SP);
+ mono_emit_unwind_op_def_cfa_reg (cfg, code, ARMREG_FP);
+ if (cfg->param_area) {
+ /* The param area is below the frame pointer */
+ code = emit_subx_sp_imm (code, cfg->param_area);
+ }
+
+ if (cfg->method->save_lmf) {
+ code = emit_setup_lmf (cfg, code, cfg->lmf_var->inst_offset, cfa_offset);
+ } else {
+ /* Save gregs */
+ code = emit_store_regset_cfa (cfg, code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, cfg->arch.saved_gregs_offset, cfa_offset, 0);
+ }
+
+ /* Setup args reg */
+ if (cfg->arch.args_reg) {
+ /* The register was already saved above */
+ code = emit_addx_imm (code, cfg->arch.args_reg, ARMREG_FP, cfg->stack_offset);
+ }
+
+ /* Save return area addr received in R8 */
+ if (cfg->vret_addr) {
+ MonoInst *ins = cfg->vret_addr;
+
+ g_assert (ins->opcode == OP_REGOFFSET);
+ code = emit_strx (code, ARMREG_R8, ins->inst_basereg, ins->inst_offset);
+ }
+
+ /* Save mrgctx received in MONO_ARCH_RGCTX_REG */
+ if (cfg->rgctx_var) {
+ MonoInst *ins = cfg->rgctx_var;
+
+ g_assert (ins->opcode == OP_REGOFFSET);
+
+ code = emit_strx (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
+ }
+
+ /*
+ * Move arguments to their registers/stack locations.
+ */
+ code = emit_move_args (cfg, code);
+
+ /* Initialize seq_point_info_var */
+ if (cfg->arch.seq_point_info_var) {
+ MonoInst *ins = cfg->arch.seq_point_info_var;
+
+ /* Initialize the variable from a GOT slot */
+ code = emit_aotconst (cfg, code, ARMREG_IP0, MONO_PATCH_INFO_SEQ_POINT_INFO, cfg->method);
+ g_assert (ins->opcode == OP_REGOFFSET);
+ code = emit_strx (code, ARMREG_IP0, ins->inst_basereg, ins->inst_offset);
+
+ /* Initialize ss_tramp_var */
+ ins = cfg->arch.ss_tramp_var;
+ g_assert (ins->opcode == OP_REGOFFSET);
+
+ code = emit_ldrx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (SeqPointInfo, ss_tramp_addr));
+ code = emit_strx (code, ARMREG_IP1, ins->inst_basereg, ins->inst_offset);
+ } else {
+ MonoInst *ins;
+
+ if (cfg->arch.ss_tramp_var) {
+ /* Initialize ss_tramp_var */
+ ins = cfg->arch.ss_tramp_var;
+ g_assert (ins->opcode == OP_REGOFFSET);
+
+ code = emit_imm64 (code, ARMREG_IP0, (guint64)&ss_trampoline);
+ code = emit_strx (code, ARMREG_IP0, ins->inst_basereg, ins->inst_offset);
+ }
+
+ if (cfg->arch.bp_tramp_var) {
+ /* Initialize bp_tramp_var */
+ ins = cfg->arch.bp_tramp_var;
+ g_assert (ins->opcode == OP_REGOFFSET);
+
+ code = emit_imm64 (code, ARMREG_IP0, (guint64)bp_trampoline);
+ code = emit_strx (code, ARMREG_IP0, ins->inst_basereg, ins->inst_offset);
+ }
+ }
+
+ max_offset = 0;
+ if (cfg->opt & MONO_OPT_BRANCH) {
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ MonoInst *ins;
+ bb->max_offset = max_offset;
+
+ MONO_BB_FOR_EACH_INS (bb, ins) {
+ max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
+ }
+ }
+ }
+ if (max_offset > 0x3ffff * 4)
+ cfg->arch.cond_branch_islands = TRUE;
+
+ return code;
+}
+
+static guint8*
+realloc_code (MonoCompile *cfg, int size)
+{
+ while (cfg->code_len + size > (cfg->code_size - 16)) {
+ cfg->code_size *= 2;
+ cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+ cfg->stat_code_reallocs++;
+ }
+ return cfg->native_code + cfg->code_len;
+}
+
+void
+mono_arch_emit_epilog (MonoCompile *cfg)
+{
+ CallInfo *cinfo;
+ int max_epilog_size;
+ guint8 *code;
+ int i;
+
+ max_epilog_size = 16 + 20*4;
+ code = realloc_code (cfg, max_epilog_size);
+
+ if (cfg->method->save_lmf) {
+ code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, cfg->lmf_var->inst_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs) - (MONO_ARCH_FIRST_LMF_REG * 8));
+ } else {
+ /* Restore gregs */
+ code = emit_load_regset (code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, cfg->arch.saved_gregs_offset);
+ }
+
+ /* Load returned vtypes into registers if needed */
+ cinfo = cfg->arch.cinfo;
+ switch (cinfo->ret.storage) {
+ case ArgVtypeInIRegs: {
+ MonoInst *ins = cfg->ret;
+
+ for (i = 0; i < cinfo->ret.nregs; ++i)
+ code = emit_ldrx (code, cinfo->ret.reg + i, ins->inst_basereg, ins->inst_offset + (i * 8));
+ break;
+ }
+ case ArgHFA: {
+ MonoInst *ins = cfg->ret;
+
+ for (i = 0; i < cinfo->ret.nregs; ++i) {
+ if (cinfo->ret.esize == 4)
+ code = emit_ldrfpw (code, cinfo->ret.reg + i, ins->inst_basereg, ins->inst_offset + cinfo->ret.foffsets [i]);
+ else
+ code = emit_ldrfpx (code, cinfo->ret.reg + i, ins->inst_basereg, ins->inst_offset + cinfo->ret.foffsets [i]);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Destroy frame */
+ code = mono_arm_emit_destroy_frame (code, cfg->stack_offset, ((1 << ARMREG_IP0) | (1 << ARMREG_IP1)));
+
+ arm_retx (code, ARMREG_LR);
+
+ g_assert (code - (cfg->native_code + cfg->code_len) < max_epilog_size);
+
+ cfg->code_len = code - cfg->native_code;
+}
+
+void
+mono_arch_emit_exceptions (MonoCompile *cfg)
+{
+ MonoJumpInfo *ji;
+ MonoClass *exc_class;
+ guint8 *code, *ip;
+ guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
+ guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
+ int i, id, size = 0;
+
+ for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
+ exc_throw_pos [i] = NULL;
+ exc_throw_found [i] = 0;
+ }
+
+ for (ji = cfg->patch_info; ji; ji = ji->next) {
+ if (ji->type == MONO_PATCH_INFO_EXC) {
+ i = mini_exception_id_by_name (ji->data.target);
+ if (!exc_throw_found [i]) {
+ size += 32;
+ exc_throw_found [i] = TRUE;
+ }
+ }
+ }
+
+ code = realloc_code (cfg, size);
+
+ /* Emit code to raise corlib exceptions */
+ for (ji = cfg->patch_info; ji; ji = ji->next) {
+ if (ji->type != MONO_PATCH_INFO_EXC)
+ continue;
+
+ ip = cfg->native_code + ji->ip.i;
+
+ id = mini_exception_id_by_name (ji->data.target);
+
+ if (exc_throw_pos [id]) {
+ /* ip points to the bcc () in OP_COND_EXC_... */
+ arm_patch_rel (ip, exc_throw_pos [id], ji->relocation);
+ ji->type = MONO_PATCH_INFO_NONE;
+ continue;
+ }
+
+ exc_throw_pos [id] = code;
+ arm_patch_rel (ip, code, ji->relocation);
+
+ /* We are being branched to from the code generated by emit_cond_exc (), the pc is in ip1 */
+
+ /* r0 = type token */
+ exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", ji->data.name);
+ code = emit_imm (code, ARMREG_R0, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
+ /* r1 = throw ip */
+ arm_movx (code, ARMREG_R1, ARMREG_IP1);
+ /* Branch to the corlib exception throwing trampoline */
+ ji->ip.i = code - cfg->native_code;
+ ji->type = MONO_PATCH_INFO_INTERNAL_METHOD;
+ ji->data.name = "mono_arch_throw_corlib_exception";
+ ji->relocation = MONO_R_ARM64_BL;
+ arm_bl (code, 0);
+ cfg->thunk_area += THUNK_SIZE;
+ }
+
+ cfg->code_len = code - cfg->native_code;
+
+ g_assert (cfg->code_len < cfg->code_size);
+}
+
+MonoInst*
+mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ return NULL;
+}
+
+gboolean
+mono_arch_print_tree (MonoInst *tree, int arity)
+{
+ return FALSE;
+}
+
+guint32
+mono_arch_get_patch_offset (guint8 *code)
+{
+ return 0;
+}
+
+gpointer
+mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
+ gpointer fail_tramp)
+{
+ int i, buf_len, imt_reg;
+ guint8 *buf, *code;
+
+#if DEBUG_IMT
+ printf ("building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable);
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+ printf ("method %d (%p) %s vtable slot %p is_equals %d chunk size %d\n", i, item->key, item->key->name, &vtable->vtable [item->value.vtable_slot], item->is_equals, item->chunk_size);
+ }
+#endif
+
+ buf_len = 0;
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+ if (item->is_equals) {
+ gboolean fail_case = !item->check_target_idx && fail_tramp;
+
+ if (item->check_target_idx || fail_case) {
+ if (!item->compare_done || fail_case) {
+ buf_len += 4 * 4 + 4;
+ }
+ buf_len += 4;
+ if (item->has_target_code) {
+ buf_len += 5 * 4;
+ } else {
+ buf_len += 6 * 4;
+ }
+ if (fail_case) {
+ buf_len += 5 * 4;
+ }
+ } else {
+ buf_len += 6 * 4;
+ }
+ } else {
+ buf_len += 6 * 4;
+ }
+ }
+
+ if (fail_tramp)
+ buf = mono_method_alloc_generic_virtual_thunk (domain, buf_len);
+ else
+ buf = mono_domain_code_reserve (domain, buf_len);
+ code = buf;
+
+ /*
+ * We are called by JITted code, which passes in the IMT argument in
+ * MONO_ARCH_RGCTX_REG (r27). We need to preserve all caller saved regs
+ * except ip0/ip1.
+ */
+ imt_reg = MONO_ARCH_RGCTX_REG;
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+
+ item->code_target = code;
+
+ if (item->is_equals) {
+ /*
+ * Check the imt argument against item->key, if equals, jump to either
+ * item->value.target_code or to vtable [item->value.vtable_slot].
+ * If fail_tramp is set, jump to it if not-equals.
+ */
+ gboolean fail_case = !item->check_target_idx && fail_tramp;
+
+ if (item->check_target_idx || fail_case) {
+ /* Compare imt_reg with item->key */
+ if (!item->compare_done || fail_case) {
+ // FIXME: Optimize this
+ code = emit_imm64 (code, ARMREG_IP0, (guint64)item->key);
+ arm_cmpx (code, imt_reg, ARMREG_IP0);
+ }
+ item->jmp_code = code;
+ arm_bcc (code, ARMCOND_NE, 0);
+ /* Jump to target if equals */
+ if (item->has_target_code) {
+ code = emit_imm64 (code, ARMREG_IP0, (guint64)item->value.target_code);
+ arm_brx (code, ARMREG_IP0);
+ } else {
+ guint64 imm = (guint64)&(vtable->vtable [item->value.vtable_slot]);
+
+ code = emit_imm64 (code, ARMREG_IP0, imm);
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
+ arm_brx (code, ARMREG_IP0);
+ }
+
+ if (fail_case) {
+ arm_patch_rel (item->jmp_code, code, MONO_R_ARM64_BCC);
+ item->jmp_code = NULL;
+ code = emit_imm64 (code, ARMREG_IP0, (guint64)fail_tramp);
+ arm_brx (code, ARMREG_IP0);
+ }
+ } else {
+ guint64 imm = (guint64)&(vtable->vtable [item->value.vtable_slot]);
+
+ code = emit_imm64 (code, ARMREG_IP0, imm);
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
+ arm_brx (code, ARMREG_IP0);
+ }
+ } else {
+ code = emit_imm64 (code, ARMREG_IP0, (guint64)item->key);
+ arm_cmpx (code, imt_reg, ARMREG_IP0);
+ item->jmp_code = code;
+ arm_bcc (code, ARMCOND_HS, 0);
+ }
+ }
+ /* Patch the branches */
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+ if (item->jmp_code && item->check_target_idx)
+ arm_patch_rel (item->jmp_code, imt_entries [item->check_target_idx]->code_target, MONO_R_ARM64_BCC);
+ }
+
+ g_assert ((code - buf) < buf_len);
+
+ mono_arch_flush_icache (buf, code - buf);
+
+ return buf;
+}
+
+GSList *
+mono_arch_get_trampolines (gboolean aot)
+{
+ return mono_arm_get_exception_trampolines (aot);
+}
+
+#else /* DISABLE_JIT */
+
+gpointer
+mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
+ gpointer fail_tramp)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif /* !DISABLE_JIT */
+
+#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
+
+void
+mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
+{
+ guint8 *code = ip;
+ guint32 native_offset = ip - (guint8*)ji->code_start;
+
+ if (ji->from_aot) {
+ SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
+
+ g_assert (native_offset % 4 == 0);
+ g_assert (info->bp_addrs [native_offset / 4] == 0);
+ info->bp_addrs [native_offset / 4] = mini_get_breakpoint_trampoline ();
+ } else {
+ /* ip points to an ldrx */
+ code += 4;
+ arm_blrx (code, ARMREG_IP0);
+ mono_arch_flush_icache (ip, code - ip);
+ }
+}
+
+void
+mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
+{
+ guint8 *code = ip;
+
+ if (ji->from_aot) {
+ guint32 native_offset = ip - (guint8*)ji->code_start;
+ SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
+
+ g_assert (native_offset % 4 == 0);
+ info->bp_addrs [native_offset / 4] = NULL;
+ } else {
+ /* ip points to an ldrx */
+ code += 4;
+ arm_nop (code);
+ mono_arch_flush_icache (ip, code - ip);
+ }
+}
+
+void
+mono_arch_start_single_stepping (void)
+{
+ ss_trampoline = mini_get_single_step_trampoline ();
+}
+
+void
+mono_arch_stop_single_stepping (void)
+{
+ ss_trampoline = NULL;
+}
+
+gboolean
+mono_arch_is_single_step_event (void *info, void *sigctx)
+{
+ /* We use soft breakpoints on arm64 */
+ return FALSE;
+}
+
+gboolean
+mono_arch_is_breakpoint_event (void *info, void *sigctx)
+{
+ /* We use soft breakpoints on arm64 */
+ return FALSE;
+}
+
+void
+mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
+{
+ g_assert_not_reached ();
+}
+
+void
+mono_arch_skip_single_step (MonoContext *ctx)
+{
+ g_assert_not_reached ();
+}
+
+gpointer
+mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
+{
+ SeqPointInfo *info;
+ MonoJitInfo *ji;
+
+ // FIXME: Add a free function
+
+ mono_domain_lock (domain);
+ info = g_hash_table_lookup (domain_jit_info (domain)->arch_seq_points,
+ code);
+ mono_domain_unlock (domain);
+
+ if (!info) {
+ ji = mono_jit_info_table_find (domain, (char*)code);
+ g_assert (ji);
+
+ info = g_malloc0 (sizeof (SeqPointInfo) + (ji->code_size / 4) * sizeof(guint8*));
+
+ info->ss_tramp_addr = &ss_trampoline;
+
+ mono_domain_lock (domain);
+ g_hash_table_insert (domain_jit_info (domain)->arch_seq_points,
+ code, info);
+ mono_domain_unlock (domain);
+ }
+
+ return info;
+}
+
+void
+mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
+{
+ ext->lmf.previous_lmf = prev_lmf;
+ /* Mark that this is a MonoLMFExt */
+ ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
+ ext->lmf.gregs [MONO_ARCH_LMF_REG_SP] = (gssize)ext;
+}
+
+#endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
+
+gboolean
+mono_arch_opcode_supported (int opcode)
+{
+ switch (opcode) {
+ case OP_ATOMIC_ADD_I4:
+ case OP_ATOMIC_ADD_I8:
+ case OP_ATOMIC_EXCHANGE_I4:
+ case OP_ATOMIC_EXCHANGE_I8:
+ case OP_ATOMIC_CAS_I4:
+ case OP_ATOMIC_CAS_I8:
+ case OP_ATOMIC_LOAD_I1:
+ case OP_ATOMIC_LOAD_I2:
+ case OP_ATOMIC_LOAD_I4:
+ case OP_ATOMIC_LOAD_I8:
+ case OP_ATOMIC_LOAD_U1:
+ case OP_ATOMIC_LOAD_U2:
+ case OP_ATOMIC_LOAD_U4:
+ case OP_ATOMIC_LOAD_U8:
+ case OP_ATOMIC_LOAD_R4:
+ case OP_ATOMIC_LOAD_R8:
+ case OP_ATOMIC_STORE_I1:
+ case OP_ATOMIC_STORE_I2:
+ case OP_ATOMIC_STORE_I4:
+ case OP_ATOMIC_STORE_I8:
+ case OP_ATOMIC_STORE_U1:
+ case OP_ATOMIC_STORE_U2:
+ case OP_ATOMIC_STORE_U4:
+ case OP_ATOMIC_STORE_U8:
+ case OP_ATOMIC_STORE_R4:
+ case OP_ATOMIC_STORE_R8:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+ return get_call_info (mp, sig);
+}
+
-#include "../../../mono-extensions/mono/mini/mini-arm64.h"
+/*
+ * mini-arm64.h
+ *
+ * Copyright 2013 Xamarin Inc
+ *
+ * Based on mini-arm.h:
+ *
+ * Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#ifndef __MONO_MINI_ARM64_H__
+#define __MONO_MINI_ARM64_H__
+
+#include <mono/arch/arm64/arm64-codegen.h>
+#include <mono/mini/mini-arm64-gsharedvt.h>
+
+#define MONO_ARCH_CPU_SPEC mono_arm64_cpu_desc
+
+#define MONO_MAX_IREGS 32
+#define MONO_MAX_FREGS 32
+
+#define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->regs [0] = (gsize)exc; } while (0)
+
+#define MONO_INIT_CONTEXT_FROM_FUNC(ctx,func) do { \
+ MONO_CONTEXT_SET_BP ((ctx), __builtin_frame_address (0)); \
+ MONO_CONTEXT_SET_SP ((ctx), __builtin_frame_address (0)); \
+ MONO_CONTEXT_SET_IP ((ctx), (func)); \
+ } while (0)
+
+#define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
+
+/* Parameters used by the register allocator */
+/* r0..r7, r9..r14 (r15 is the imt/rgctx reg) */
+#define MONO_ARCH_CALLEE_REGS 0xfeff
+/* r19..r28 */
+#define MONO_ARCH_CALLEE_SAVED_REGS (0x3ff << 19)
+
+/* v16/v17 is reserved for a scratch reg */
+#define MONO_ARCH_CALLEE_FREGS 0xfffc00ff
+/* v8..v15 */
+#define MONO_ARCH_CALLEE_SAVED_FREGS 0xff00
+
+#define MONO_ARCH_USE_FPSTACK FALSE
+#define MONO_ARCH_FPSTACK_SIZE 0
+
+#define MONO_ARCH_INST_SREG2_MASK(ins) (0)
+
+#define MONO_ARCH_INST_FIXED_REG(desc) ((desc) == 'a' ? ARMREG_R0 : -1)
+
+#define MONO_ARCH_INST_IS_REGPAIR(desc) (0)
+
+#define MONO_ARCH_INST_IS_FLOAT(desc) ((desc) == 'f')
+
+#define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (-1)
+
+#define MONO_ARCH_USE_FPSTACK FALSE
+
+#define MONO_ARCH_FRAME_ALIGNMENT 16
+
+#define MONO_ARCH_CODE_ALIGNMENT 32
+
+/* callee saved regs + fp + sp */
+#define MONO_ARCH_LMF_REGS ((0x3ff << 19) | (1 << ARMREG_FP) | (1 << ARMREG_SP))
+#define MONO_ARCH_NUM_LMF_REGS (10 + 2)
+#define MONO_ARCH_FIRST_LMF_REG ARMREG_R19
+#define MONO_ARCH_LMF_REG_FP 10
+#define MONO_ARCH_LMF_REG_SP 11
+
+struct MonoLMF {
+ /*
+ * If the second lowest bit is set to 1, then this is a MonoLMFExt structure, and
+ * the other fields are not valid.
+ */
+ gpointer previous_lmf;
+ gpointer lmf_addr;
+ mgreg_t pc;
+ mgreg_t gregs [MONO_ARCH_NUM_LMF_REGS];
+};
+
+/* Structure used by the sequence points in AOTed code */
+typedef struct {
+ gpointer ss_trigger_page;
+ gpointer bp_trigger_page;
+ gpointer ss_tramp_addr;
+ guint8* bp_addrs [MONO_ZERO_LEN_ARRAY];
+} SeqPointInfo;
+
+#define PARAM_REGS 8
+#define FP_PARAM_REGS 8
+
+#define DYN_CALL_STACK_ARGS 6
+
+typedef struct {
+ /* The +1 is for r8 */
+ mgreg_t regs [PARAM_REGS + 1 + DYN_CALL_STACK_ARGS];
+ mgreg_t res, res2;
+ guint8 *ret;
+ double fpregs [FP_PARAM_REGS];
+ int n_fpargs, n_fpret;
+ guint8 buffer [256];
+} DynCallArgs;
+
+typedef struct {
+ gpointer cinfo;
+ int saved_gregs_offset;
+ /* Points to arguments received on the stack */
+ int args_reg;
+ gboolean cond_branch_islands;
+ gpointer vret_addr_loc;
+ gpointer seq_point_info_var;
+ gpointer ss_tramp_var;
+ gpointer bp_tramp_var;
+ guint8 *thunks;
+ int thunks_size;
+} MonoCompileArch;
+
+#define MONO_ARCH_EMULATE_FREM 1
+#define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS 1
+#define MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS 1
+#define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS 1
+#define MONO_ARCH_NEED_DIV_CHECK 1
+#define MONO_ARCH_EMULATE_MUL_OVF 1
+#define MONO_ARCH_HAVE_IMT 1
+#define MONO_ARCH_HAVE_OP_TAIL_CALL 1
+#define MONO_ARCH_THIS_AS_FIRST_ARG 1
+#define MONO_ARCH_RGCTX_REG ARMREG_R15
+#define MONO_ARCH_IMT_REG MONO_ARCH_RGCTX_REG
+#define MONO_ARCH_VTABLE_REG ARMREG_R0
+#define MONO_ARCH_EXC_REG ARMREG_R0
+#define MONO_ARCH_HAVE_XP_UNWIND 1
+#define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
+#define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
+#define MONO_ARCH_USE_SIGACTION 1
+#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
+#define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
+#define MONO_ARCH_GSHARED_SUPPORTED 1
+#define MONO_ARCH_AOT_SUPPORTED 1
+#define MONO_ARCH_LLVM_SUPPORTED 1
+#define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
+#define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
+#define MONO_ARCH_HAVE_GET_TRAMPOLINES 1
+#define MONO_ARCH_DYN_CALL_SUPPORTED 1
+#define MONO_ARCH_DYN_CALL_PARAM_AREA (DYN_CALL_STACK_ARGS * 8)
+#define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
+#ifndef TARGET_ANDROID
+#define MONO_ARCH_GSHAREDVT_SUPPORTED 1
+#endif
+#define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
+#define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
+#define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1
+#ifndef MONO_CROSS_COMPILE
+#define MONO_ARCH_ENABLE_MONO_LMF_VAR 1
+#endif
+#define MONO_ARCH_HAVE_OP_GET_EX_OBJ 1
+#define MONO_ARCH_HAVE_OBJC_GET_SELECTOR 1
+#define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1
+#define MONO_ARCH_HAVE_PATCH_CODE_NEW 1
+#define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1
+#define MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION 1
+#define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1
+
+#ifdef TARGET_IOS
+
+#define MONO_ARCH_REDZONE_SIZE 128
+
+#else
+
+#define MONO_ARCH_REDZONE_SIZE 0
+#if !defined(__PIC__)
+#define MONO_ARCH_HAVE_TLS_GET 1
+#endif
+#define MONO_ARCH_HAVE_TLS_GET_REG 1
+
+#endif
+
+#if defined(TARGET_APPLETVOS)
+#define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1
+#endif
+
+/* Relocations */
+#define MONO_R_ARM64_B 1
+#define MONO_R_ARM64_BCC 2
+#define MONO_R_ARM64_IMM 3
+#define MONO_R_ARM64_BL 4
+#define MONO_R_ARM64_BL_SHORT 5
+#define MONO_R_ARM64_CBZ 6
+
+
+typedef enum {
+ ArgInIReg,
+ ArgInFReg,
+ ArgInFRegR4,
+ ArgOnStack,
+ ArgOnStackR8,
+ ArgOnStackR4,
+ /*
+ * Vtype passed in consecutive int registers.
+ * ainfo->reg is the firs register,
+ * ainfo->nregs is the number of registers,
+ * ainfo->size is the size of the structure.
+ */
+ ArgVtypeInIRegs,
+ ArgVtypeByRef,
+ ArgVtypeByRefOnStack,
+ ArgVtypeOnStack,
+ ArgHFA,
+ ArgNone
+} ArgStorage;
+
+typedef struct {
+ ArgStorage storage;
+ int reg;
+ /* ArgOnStack */
+ int offset;
+ /* ArgVtypeInIRegs/ArgHFA */
+ int nregs, size;
+ /* ArgHFA */
+ int esize;
+ /* ArgHFA */
+ /* The offsets of the float values inside the arg */
+ guint16 foffsets [4];
+ /* ArgOnStack */
+ int slot_size;
+ /* hfa */
+ int nfregs_to_skip;
+ gboolean sign;
+ gboolean gsharedvt;
+ gboolean hfa;
+} ArgInfo;
+
+typedef struct {
+ int nargs;
+ int gr, fr, stack_usage;
+ ArgInfo ret;
+ ArgInfo sig_cookie;
+ ArgInfo args [1];
+} CallInfo;
+
+
+guint8* mono_arm_emit_imm64 (guint8 *code, int dreg, gint64 imm);
+
+guint8* mono_arm_emit_ldrx (guint8 *code, int rt, int rn, int imm);
+
+guint8* mono_arm_emit_destroy_frame (guint8 *code, int stack_offset, guint64 temp_regs);
+
+guint8* mono_arm_emit_store_regset (guint8 *code, guint64 regs, int basereg, int offset);
+
+guint8* mono_arm_emit_store_regarray (guint8 *code, guint64 regs, int basereg, int offset);
+
+guint8* mono_arm_emit_load_regarray (guint8 *code, guint64 regs, int basereg, int offset);
+
+/* MonoJumpInfo **ji */
+guint8* mono_arm_emit_aotconst (gpointer ji, guint8 *code, guint8 *code_start, int dreg, guint32 patch_type, gconstpointer data);
+
+void mono_arm_patch (guint8 *code, guint8 *target, int relocation);
+
+void mono_arm_throw_exception (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp_regs, gboolean corlib, gboolean rethrow);
+
+void mono_arm_gsharedvt_init (void);
+
+GSList* mono_arm_get_exception_trampolines (gboolean aot);
+
+void mono_arm_resume_unwind (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp_regs, gboolean corlib, gboolean rethrow);
+
+CallInfo* mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);
+
+#endif /* __MONO_MINI_ARM64_H__ */
#include "config.h"
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/mini/mini-cross-helpers.c"
+#include <stdio.h>
+
+#include "config.h"
+
+#include "mini.h"
+#include "tasklets.h"
+#include <mono/metadata/abi-details.h>
+
+void
+mono_dump_metadata_offsets (void);
+
+void
+mono_metadata_cross_helpers_run (void);
+
+
+static void
+mono_dump_jit_offsets (void)
+{
+#ifdef USED_CROSS_COMPILER_OFFSETS
+ g_print ("#error not using native offsets\n");
#else
+ mono_dump_metadata_offsets ();
+
+ g_print ("#ifndef DISABLE_JIT_OFFSETS\n");
+ g_print ("#define USED_CROSS_COMPILER_OFFSETS\n");
+#define DISABLE_METADATA_OFFSETS
+#define DECL_OFFSET2(struct,field,offset) this_should_not_happen
+#define DECL_ALIGN2(type,size) this_should_not_happen
-void mono_cross_helpers_run (void);
+#define DECL_OFFSET(struct,field) g_print ("DECL_OFFSET2(%s,%s,%d)\n", #struct, #field, (int)MONO_STRUCT_OFFSET (struct, field));
+#define DECL_ALIGN(type)
+#define DECL_SIZE2(type,size) this_should_not_happen
+#define DECL_SIZE(type)
+#include <mono/metadata/object-offsets.h>
+
+ g_print ("#endif //disable jit check\n");
+ g_print ("#endif //cross compiler checks\n");
+ g_print ("#endif //gc check\n");
+ g_print ("#endif //os check\n");
+ g_print ("#endif //arch check\n");
+ g_print ("#endif //USED_CROSS_COMPILER_OFFSETS check\n");
+#endif
+}
void
mono_cross_helpers_run (void)
{
-}
+#if defined (HAS_CROSS_COMPILER_OFFSETS) && !defined (MONO_CROSS_COMPILE)
+ gboolean is_broken = FALSE;
+#endif
+
+#ifndef USED_CROSS_COMPILER_OFFSETS
+ if (g_getenv ("DUMP_CROSS_OFFSETS"))
+ mono_dump_jit_offsets ();
#endif
+
+#if defined (HAS_CROSS_COMPILER_OFFSETS) && !defined (MONO_CROSS_COMPILE)
+ mono_metadata_cross_helpers_run ();
+
+#define DISABLE_METADATA_OFFSETS
+#define USE_CROSS_COMPILE_OFFSETS
+#define DECL_OFFSET(struct,field) this_should_not_happen_for_cross_fields
+#define DECL_OFFSET2(struct,field,offset) \
+ if ((int)G_STRUCT_OFFSET (struct, field) != offset) { \
+ g_print (#struct ":" #field " invalid struct offset %d (expected %d)\n", \
+ offset, \
+ (int)G_STRUCT_OFFSET (struct, field)); \
+ is_broken = TRUE; \
+ }
+#define DECL_ALIGN(name,type) this_should_not_happen_for_cross_align
+#define DECL_ALIGN2(name,size) \
+ if (MONO_ALIGN_ ## name != size) { \
+ g_print (#name ": invalid alignment %d (expected %d)\n", \
+ size, \
+ MONO_ALIGN_ ## name); \
+ is_broken = TRUE; \
+ }
+#define DECL_SIZE(type) this_should_not_happen_for_cross_size
+#define DECL_SIZE2(name,size) \
+ if (MONO_SIZEOF_ ## name != size) { \
+ g_print (#name ": invalid size %d (expected %d)\n", \
+ size, \
+ MONO_SIZEOF_ ## name); \
+ is_broken = TRUE; \
+ }
+
+#include <mono/metadata/object-offsets.h>
+
+ g_assert (!is_broken);
+#endif
+}
* Copyright 2003-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*
- * See LICENSE for licensing information.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <signal.h>
--- /dev/null
+/*
+ * mini-exceptions-native-unwinder.c: libcorkscrew-based native unwinder
+ *
+ * Authors:
+ * Alex Rønne Petersen (alexrp@xamarin.com)
+ *
+ * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include <config.h>
+
+/*
+ * Attempt to handle native SIGSEGVs with libunwind or libcorkscrew.
+ */
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#include <mono/utils/mono-signal-handler.h>
+#include "mini.h"
+
+#if defined (PLATFORM_ANDROID)
+
+#include <signal.h>
+#include <sys/types.h>
+#include <mono/utils/mono-dl.h>
+
+#define UNW_LOCAL_ONLY
+#undef _U /* ctype.h apparently defines this and it screws up the libunwind headers. */
+#include "android-libunwind/libunwind.h"
+#define _U 0x01
+
+#define FUNC_NAME_LENGTH 512
+#define FRAMES_TO_UNWIND 256
+
+/* Expand the SYM argument. */
+#define LOAD_SYM(DL, ERR, SYM, VAR) _LOAD_SYM(DL, ERR, SYM, VAR)
+#define _LOAD_SYM(DL, ERR, SYM, VAR) \
+ do { \
+ if ((ERR = mono_dl_symbol (DL, #SYM, (void **) &VAR))) { \
+ mono_dl_close (DL); \
+ return ERR; \
+ } \
+ } while (0)
+
+typedef int (*unw_init_local_t) (unw_cursor_t *, unw_context_t *);
+typedef int (*unw_get_reg_t) (unw_cursor_t *, int, unw_word_t *);
+typedef int (*unw_get_proc_name_t) (unw_cursor_t *, char *, size_t, unw_word_t *);
+typedef int (*unw_step_t) (unw_cursor_t *);
+
+static char *
+mono_extension_handle_native_sigsegv_libunwind (void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
+{
+ char *dl_err;
+ int unw_err;
+
+ unw_init_local_t unw_init_local_fn;
+ unw_get_reg_t unw_get_reg_fn;
+ unw_get_proc_name_t unw_get_proc_name_fn;
+ unw_step_t unw_step_fn;
+
+ unw_cursor_t cursor;
+
+ size_t frames = 0;
+
+ MonoDl *dl = mono_dl_open ("libunwind.so", MONO_DL_LAZY, &dl_err);
+
+ if (!dl)
+ return dl_err;
+
+ LOAD_SYM (dl, dl_err, UNW_OBJ (init_local), unw_init_local_fn);
+ LOAD_SYM (dl, dl_err, UNW_OBJ (get_reg), unw_get_reg_fn);
+ LOAD_SYM (dl, dl_err, UNW_OBJ (get_proc_name), unw_get_proc_name_fn);
+ LOAD_SYM (dl, dl_err, UNW_OBJ (step), unw_step_fn);
+
+ if ((unw_err = unw_init_local_fn (&cursor, ctx))) {
+ mono_dl_close (dl);
+
+ return g_strdup_printf ("unw_init_local () returned %d", unw_err);
+ }
+
+ do {
+ int reg_err;
+
+ unw_word_t ip, off;
+ char name [FUNC_NAME_LENGTH];
+
+ if ((reg_err = unw_get_reg_fn (&cursor, UNW_REG_IP, &ip))) {
+ mono_runtime_printf_err ("unw_get_reg (UNW_REG_IP) returned %d", reg_err);
+ break;
+ }
+
+ reg_err = unw_get_proc_name_fn (&cursor, name, FUNC_NAME_LENGTH, &off);
+
+ if (reg_err == -UNW_ENOINFO)
+ strcpy (name, "???");
+
+ mono_runtime_printf_err (" at %s+%zu [0x%zx]", name, off, ip);
+
+ unw_err = unw_step_fn (&cursor);
+ frames++;
+ } while (unw_err > 0 && frames < FRAMES_TO_UNWIND);
+
+ if (unw_err < 0)
+ mono_runtime_printf_err ("unw_step () returned %d", unw_err);
+
+ mono_dl_close (dl);
+
+ return NULL;
+}
+
+/*
+ * This code is based on the AOSP header system/core/include/corkscrew/backtrace.h.
+ *
+ * This is copied here because libcorkscrew is not a stable library and the header (and
+ * other headers that it depends on) will eventually go away.
+ *
+ * We can probably remove this one day when libunwind becomes the norm.
+ */
+
+typedef struct {
+ uintptr_t absolute_pc;
+ uintptr_t stack_top;
+ size_t stack_size;
+} backtrace_frame_t;
+
+typedef struct {
+ uintptr_t relative_pc;
+ uintptr_t relative_symbol_addr;
+ char *map_name;
+ char *symbol_name;
+ char *demangled_name;
+} backtrace_symbol_t;
+
+typedef void (*get_backtrace_symbols_t) (const backtrace_frame_t *backtrace, size_t frames, backtrace_symbol_t *backtrace_symbols);
+typedef void (*free_backtrace_symbols_t) (backtrace_symbol_t *backtrace_symbols, size_t frames);
+
+enum {
+ MAX_BACKTRACE_LINE_LENGTH = 800,
+};
+
+/* Internals that we're exploiting to work in a signal handler. Only works on ARM/x86. */
+
+typedef struct map_info_t map_info_t;
+
+typedef ssize_t (*unwind_backtrace_signal_arch_t) (siginfo_t *si, void *sc, const map_info_t *lst, backtrace_frame_t *bt, size_t ignore_depth, size_t max_depth);
+typedef map_info_t *(*acquire_my_map_info_list_t) (void);
+typedef void (*release_my_map_info_list_t) (map_info_t *milist);
+
+static char *
+mono_extension_handle_native_sigsegv_libcorkscrew (void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
+{
+#if defined (__arm__) || defined (__i386__)
+ char *dl_err;
+
+ get_backtrace_symbols_t get_backtrace_symbols;
+ free_backtrace_symbols_t free_backtrace_symbols;
+ unwind_backtrace_signal_arch_t unwind_backtrace_signal_arch;
+ acquire_my_map_info_list_t acquire_my_map_info_list;
+ release_my_map_info_list_t release_my_map_info_list;
+
+ backtrace_frame_t frames [FRAMES_TO_UNWIND];
+ backtrace_symbol_t symbols [FRAMES_TO_UNWIND];
+
+ map_info_t *map_info;
+ ssize_t frames_unwound;
+ size_t i;
+
+ MonoDl *dl = mono_dl_open ("libcorkscrew.so", MONO_DL_LAZY, &dl_err);
+
+ if (!dl)
+ return dl_err;
+
+ LOAD_SYM (dl, dl_err, get_backtrace_symbols, get_backtrace_symbols);
+ LOAD_SYM (dl, dl_err, free_backtrace_symbols, free_backtrace_symbols);
+ LOAD_SYM (dl, dl_err, unwind_backtrace_signal_arch, unwind_backtrace_signal_arch);
+ LOAD_SYM (dl, dl_err, acquire_my_map_info_list, acquire_my_map_info_list);
+ LOAD_SYM (dl, dl_err, release_my_map_info_list, release_my_map_info_list);
+
+ map_info = acquire_my_map_info_list ();
+ frames_unwound = unwind_backtrace_signal_arch (info, ctx, map_info, frames, 0, FRAMES_TO_UNWIND);
+ release_my_map_info_list (map_info);
+
+ if (frames_unwound == -1) {
+ mono_dl_close (dl);
+
+ return g_strdup ("unwind_backtrace_signal_arch () returned -1");
+ }
+
+ get_backtrace_symbols (frames, frames_unwound, symbols);
+
+ for (i = 0; i < frames_unwound; i++) {
+ backtrace_frame_t *frame = frames + i;
+ backtrace_symbol_t *symbol = symbols + i;
+
+ const char *name = symbol->demangled_name ? symbol->demangled_name : (symbol->symbol_name ? symbol->symbol_name : "???");
+ uintptr_t off = symbol->relative_pc - symbol->relative_symbol_addr;
+ uintptr_t ip = frame->absolute_pc;
+
+ mono_runtime_printf_err (" at %s+%zu [0x%zx]", name, off, ip);
+ }
+
+ free_backtrace_symbols (symbols, frames_unwound);
+
+ mono_dl_close (dl);
+
+ return NULL;
+#else
+ return g_strdup ("libcorkscrew is only supported on 32-bit ARM/x86");
+#endif
+}
+
+void
+mono_exception_native_unwind (void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
+{
+ char *unwind_err, *corkscrew_err;
+
+ mono_runtime_printf_err ("\nAttempting native Android stacktrace:\n");
+
+ unwind_err = mono_extension_handle_native_sigsegv_libunwind (ctx, info);
+
+ if (unwind_err) {
+ corkscrew_err = mono_extension_handle_native_sigsegv_libcorkscrew (ctx, info);
+
+ if (corkscrew_err) {
+ mono_runtime_printf_err ("\tCould not unwind with `libunwind.so`: %s", unwind_err);
+ mono_runtime_printf_err ("\tCould not unwind with `libcorkscrew.so`: %s", corkscrew_err);
+ mono_runtime_printf_err ("\n\tNo options left to get a native stacktrace :-(");
+
+ g_free (corkscrew_err);
+ }
+
+ g_free (unwind_err);
+ }
+}
+
+#else
+
+void
+mono_exception_native_unwind (void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
+{
+}
+
+#endif
* Copyright 2001-2003 Ximian, Inc.
* Copyright 2003-2008 Novell, Inc.
* Copyright 2011 Xamarin Inc (http://www.xamarin.com).
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include "mini-llvm-cpp.h"
#endif
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/mini/mini-exceptions.c"
-#endif
-
#ifndef MONO_ARCH_CONTEXT_DEF
#define MONO_ARCH_CONTEXT_DEF
#endif
static gboolean
mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception)
{
+ MonoError error;
MonoDomain *domain = mono_domain_get ();
MonoJitInfo *ji = NULL;
static int (*call_filter) (MonoContext *, gpointer) = NULL;
mono_ex = (MonoException*)obj;
initial_trace_ips = mono_ex->trace_ips;
- if (mono_object_isinst (obj, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
mono_ex = (MonoException*)obj;
initial_trace_ips = mono_ex->trace_ips;
} else {
+ mono_error_assert_ok (&error);
mono_ex = NULL;
}
}
}
- if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, &error)) {
setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
g_slist_free (dynamic_methods);
MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
return TRUE;
}
+ mono_error_cleanup (&error);
}
}
obj = (MonoObject *)mono_get_exception_null_reference ();
}
- if (!mono_object_isinst (obj, mono_defaults.exception_class)) {
+ if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
+ mono_error_assert_ok (&error);
non_exception = obj;
obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, &error);
mono_error_assert_ok (&error);
;
}
- if (mono_object_isinst (obj, mono_defaults.exception_class)) {
+ if (mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
mono_ex = (MonoException*)obj;
} else {
+ mono_error_assert_ok (&error);
mono_ex = NULL;
}
filter_idx ++;
}
+ mono_error_init (&error);
if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
- mono_object_isinst (ex_obj, catch_class)) || filtered) {
+ mono_object_isinst_checked (ex_obj, catch_class, &error)) || filtered) {
/*
* This guards against the situation that we abort a thread that is executing a finally clause
* that was called by the EH machinery. It won't have a guard trampoline installed, so we must
return 0;
}
+ mono_error_cleanup (&error);
if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
if (mono_trace_is_enabled () && mono_trace_eval (method))
g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
}
#endif
}
-#elif defined (ENABLE_EXTENSION_MODULE)
- mono_extension_handle_native_sigsegv (ctx, info);
+#else
+ mono_exception_native_unwind (ctx, info);
#endif
/*
MonoJitTlsData *jit_tls = mono_get_jit_tls ();
MonoException *mono_ex;
- if (!mono_object_isinst (ex, mono_defaults.exception_class)) {
+ if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, &error)) {
+ mono_error_assert_ok (&error);
mono_ex = mono_get_exception_runtime_wrapped_checked (ex, &error);
mono_error_assert_ok (&error);
}
gint32
mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
{
+ MonoError error;
MonoJitTlsData *jit_tls = mono_get_jit_tls ();
MonoObject *exc;
gint32 index = -1;
catch_class = ei->data.catch_class;
if (catch_class->byval_arg.type == MONO_TYPE_VAR || catch_class->byval_arg.type == MONO_TYPE_MVAR || catch_class->byval_arg.type == MONO_TYPE_GENERICINST) {
- MonoError error;
MonoGenericContext context;
MonoType *inflated_type;
}
// FIXME: Handle edge cases handled in get_exception_catch_class
- if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (exc, catch_class)) {
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, &error)) {
index = ei->clause_index;
break;
- } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+ } else
+ mono_error_assert_ok (&error);
+
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
g_assert_not_reached ();
}
}
*
* Copyright 2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
/*
- * generic-sharing.c: Support functions for generic sharing.
+ * mini-generic-sharing.c: Support functions for generic sharing.
*
* Author:
* Mark Probst (mark.probst@gmail.com)
*
* Copyright 2007-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
return mrgctx;
}
-
-static gboolean
-generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
- gboolean allow_partial);
-
static gboolean
type_is_sharable (MonoType *type, gboolean allow_type_vars, gboolean allow_partial)
{
if (allow_partial && !type->byref && type->type == MONO_TYPE_GENERICINST && MONO_TYPE_ISSTRUCT (type)) {
MonoGenericClass *gclass = type->data.generic_class;
- if (gclass->context.class_inst && !generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
+ if (gclass->context.class_inst && !mini_generic_inst_is_sharable (gclass->context.class_inst, allow_type_vars, allow_partial))
return FALSE;
- if (gclass->context.method_inst && !generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
+ if (gclass->context.method_inst && !mini_generic_inst_is_sharable (gclass->context.method_inst, allow_type_vars, allow_partial))
return FALSE;
if (mono_class_is_nullable (mono_class_from_mono_type (type)))
return FALSE;
return FALSE;
}
-static gboolean
-generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
+gboolean
+mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
gboolean allow_partial)
{
int i;
{
g_assert (context->class_inst || context->method_inst);
- if (context->class_inst && !generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
+ if (context->class_inst && !mini_generic_inst_is_sharable (context->class_inst, allow_type_vars, allow_partial))
return FALSE;
- if (context->method_inst && !generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
+ if (context->method_inst && !mini_generic_inst_is_sharable (context->method_inst, allow_type_vars, allow_partial))
return FALSE;
return TRUE;
}
static gboolean gshared_supported;
-static gboolean gsharedvt_supported;
void
mono_set_generic_sharing_supported (gboolean supported)
gshared_supported = supported;
}
-void
-mono_set_generic_sharing_vt_supported (gboolean supported)
-{
- gsharedvt_supported = supported;
-}
void
mono_set_partial_sharing_supported (gboolean supported)
if (all_vt || gsharedvt) {
type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]);
} else {
- /* These types match the ones in generic_inst_is_sharable () */
+ /* These types match the ones in mini_generic_inst_is_sharable () */
type_argv [i] = get_shared_type (shared_inst->type_argv [i], inst->type_argv [i]);
}
}
return slot;
}
-#if defined(ENABLE_GSHAREDVT)
+static gboolean gsharedvt_supported;
+
+void
+mono_set_generic_sharing_vt_supported (gboolean supported)
+{
+ gsharedvt_supported = supported;
+}
+
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+
+/*
+ * mini_is_gsharedvt_type:
+ *
+ * Return whenever T references type arguments instantiated with gshared vtypes.
+ */
+gboolean
+mini_is_gsharedvt_type (MonoType *t)
+{
+ int i;
+
+ if (t->byref)
+ return FALSE;
+ if ((t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->gshared_constraint && t->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE)
+ return TRUE;
+ else if (t->type == MONO_TYPE_GENERICINST) {
+ MonoGenericClass *gclass = t->data.generic_class;
+ MonoGenericContext *context = &gclass->context;
+ MonoGenericInst *inst;
+
+ inst = context->class_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (mini_is_gsharedvt_type (inst->type_argv [i]))
+ return TRUE;
+ }
+ inst = context->method_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (mini_is_gsharedvt_type (inst->type_argv [i]))
+ return TRUE;
+ }
+
+ return FALSE;
+ } else {
+ return FALSE;
+ }
+}
+
+gboolean
+mini_is_gsharedvt_klass (MonoClass *klass)
+{
+ return mini_is_gsharedvt_type (&klass->byval_arg);
+}
+
+gboolean
+mini_is_gsharedvt_signature (MonoMethodSignature *sig)
+{
+ int i;
+
+ if (sig->ret && mini_is_gsharedvt_type (sig->ret))
+ return TRUE;
+ for (i = 0; i < sig->param_count; ++i) {
+ if (mini_is_gsharedvt_type (sig->params [i]))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * mini_is_gsharedvt_variable_type:
+ *
+ * Return whenever T refers to a GSHAREDVT type whose size differs depending on the values of type parameters.
+ */
+gboolean
+mini_is_gsharedvt_variable_type (MonoType *t)
+{
+ if (!mini_is_gsharedvt_type (t))
+ return FALSE;
+ if (t->type == MONO_TYPE_GENERICINST) {
+ MonoGenericClass *gclass = t->data.generic_class;
+ MonoGenericContext *context = &gclass->context;
+ MonoGenericInst *inst;
+ int i;
+
+ if (t->data.generic_class->container_class->byval_arg.type != MONO_TYPE_VALUETYPE || t->data.generic_class->container_class->enumtype)
+ return FALSE;
+
+ inst = context->class_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
+ return TRUE;
+ }
+ inst = context->method_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (mini_is_gsharedvt_variable_type (inst->type_argv [i]))
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+is_variable_size (MonoType *t)
+{
+ int i;
+
+ if (t->byref)
+ return FALSE;
+
+ if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) {
+ MonoGenericParam *param = t->data.generic_param;
+
+ if (param->gshared_constraint && param->gshared_constraint->type != MONO_TYPE_VALUETYPE && param->gshared_constraint->type != MONO_TYPE_GENERICINST)
+ return FALSE;
+ if (param->gshared_constraint && param->gshared_constraint->type == MONO_TYPE_GENERICINST)
+ return is_variable_size (param->gshared_constraint);
+ return TRUE;
+ }
+ if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class->byval_arg.type == MONO_TYPE_VALUETYPE) {
+ MonoGenericClass *gclass = t->data.generic_class;
+ MonoGenericContext *context = &gclass->context;
+ MonoGenericInst *inst;
+
+ inst = context->class_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (is_variable_size (inst->type_argv [i]))
+ return TRUE;
+ }
+ inst = context->method_inst;
+ if (inst) {
+ for (i = 0; i < inst->type_argc; ++i)
+ if (is_variable_size (inst->type_argv [i]))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_sharable_inst (MonoGenericInst *inst)
+{
+ int i;
+ gboolean has_vt = FALSE;
+
+ for (i = 0; i < inst->type_argc; ++i) {
+ MonoType *type = inst->type_argv [i];
+
+ if ((MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_is_gsharedvt_type (type)) {
+ } else {
+ has_vt = TRUE;
+ }
+ }
-#include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
+ return has_vt;
+}
+
+gboolean
+mini_is_gsharedvt_sharable_method (MonoMethod *method)
+{
+ MonoMethodSignature *sig;
+ /*
+ * A method is gsharedvt if:
+ * - it has type parameters instantiated with vtypes
+ */
+ if (!gsharedvt_supported)
+ return FALSE;
+ if (method->is_inflated) {
+ MonoMethodInflated *inflated = (MonoMethodInflated*)method;
+ MonoGenericContext *context = &inflated->context;
+ MonoGenericInst *inst;
+
+ if (context->class_inst && context->method_inst) {
+ /* At least one inst has to be gsharedvt sharable, and the other normal or gsharedvt sharable */
+ gboolean vt1 = mini_is_gsharedvt_sharable_inst (context->class_inst);
+ gboolean vt2 = mini_is_gsharedvt_sharable_inst (context->method_inst);
+
+ if ((vt1 && vt2) ||
+ (vt1 && mini_generic_inst_is_sharable (context->method_inst, TRUE, FALSE)) ||
+ (vt2 && mini_generic_inst_is_sharable (context->class_inst, TRUE, FALSE)))
+ ;
+ else
+ return FALSE;
+ } else {
+ inst = context->class_inst;
+ if (inst && !mini_is_gsharedvt_sharable_inst (inst))
+ return FALSE;
+ inst = context->method_inst;
+ if (inst && !mini_is_gsharedvt_sharable_inst (inst))
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+
+ sig = mono_method_signature (mono_method_get_declaring_generic_method (method));
+ if (!sig)
+ return FALSE;
+
+ /*
+ if (mini_is_gsharedvt_variable_signature (sig))
+ return FALSE;
+ */
+
+ //DEBUG ("GSHAREDVT SHARABLE: %s\n", mono_method_full_name (method, TRUE));
+
+ return TRUE;
+}
+
+/*
+ * mini_is_gsharedvt_variable_signature:
+ *
+ * Return whenever the calling convention used to call SIG varies depending on the values of type parameters used by SIG,
+ * i.e. FALSE for swap(T[] arr, int i, int j), TRUE for T get_t ().
+ */
+gboolean
+mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
+{
+ int i;
+
+ if (sig->ret && is_variable_size (sig->ret))
+ return TRUE;
+ for (i = 0; i < sig->param_count; ++i) {
+ MonoType *t = sig->params [i];
+
+ if (is_variable_size (t))
+ return TRUE;
+ }
+ return FALSE;
+}
#else
gboolean
return FALSE;
}
-#endif /* !MONOTOUCH */
+#endif /* !MONO_ARCH_GSHAREDVT_SUPPORTED */
//
// (C) 2009-2011 Novell, Inc.
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
//
*
* Copyright 2009-2011 Novell Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
#define __STDC_CONSTANT_MACROS
#endif
-#include "llvm-c/Core.h"
-#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/BitWriter.h"
#include "llvm-c/Analysis.h"
MonoClass *exc_class;
LLVMValueRef args [2];
LLVMValueRef callee;
+ gboolean no_pc = FALSE;
+
+ if (IS_TARGET_AMD64)
+ /* Some platforms don't require the pc argument */
+ no_pc = TRUE;
ex_bb = gen_bb (ctx, "EX_BB");
if (ctx->llvm_only)
LLVMTypeRef sig;
const char *icall_name;
- sig = LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), LLVMPointerType (LLVMInt8Type (), 0), FALSE);
+ if (no_pc)
+ sig = LLVMFunctionType1 (LLVMVoidType (), LLVMInt32Type (), FALSE);
+ else
+ sig = LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), LLVMPointerType (LLVMInt8Type (), 0), FALSE);
icall_name = "llvm_throw_corlib_exception_abs_trampoline";
if (ctx->cfg->compile_aot) {
}
}
- if (IS_TARGET_X86 || IS_TARGET_AMD64)
- args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token - MONO_TOKEN_TYPE_DEF, FALSE);
- else
- args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token, FALSE);
+ args [0] = LLVMConstInt (LLVMInt32Type (), exc_class->type_token - MONO_TOKEN_TYPE_DEF, FALSE);
/*
* The LLVM mono branch contains changes so a block address can be passed as an
* argument to a call.
*/
- args [1] = LLVMBlockAddress (ctx->lmethod, ex_bb);
- emit_call (ctx, bb, &builder, callee, args, 2);
+ if (no_pc) {
+ emit_call (ctx, bb, &builder, callee, args, 1);
+ } else {
+ args [1] = LLVMBlockAddress (ctx->lmethod, ex_bb);
+ emit_call (ctx, bb, &builder, callee, args, 2);
+ }
LLVMBuildUnreachable (builder);
+/*
+ * magic-types.c: intrinsics for variable sized int/floats
+ *
+ * Author:
+ * Rodrigo Kumpera (kumpera@gmail.com)
+ *
+ * (C) 2013 Xamarin
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
#include <config.h>
+#include <stdio.h>
+
+#include "mini.h"
+#include "ir-emit.h"
+#include "glib.h"
+
+
+typedef struct {
+ const char *op_name;
+ short op_table[4];
+} IntIntrisic;
+
+typedef struct {
+ short op_index;
+ short big_stack_type;
+ short small_stack_type;
+ short stack_type;
+ short conv_4_to_8;
+ short conv_8_to_4;
+ short move;
+ short inc_op;
+ short dec_op;
+ short store_op;
+ short compare_op;
+} MagicTypeInfo;
+
-#if defined(MONO_NATIVE_TYPES)
+#if SIZEOF_VOID_P == 8
+#define OP_PT_ADD OP_LADD
+#define OP_PT_SUB OP_LSUB
+#define OP_PT_MUL OP_LMUL
+#define OP_PT_DIV OP_LDIV
+#define OP_PT_REM OP_LREM
+#define OP_PT_NEG OP_LNEG
+#define OP_PT_AND OP_LAND
+#define OP_PT_OR OP_LOR
+#define OP_PT_XOR OP_LXOR
+#define OP_PT_NOT OP_LNOT
+#define OP_PT_SHL OP_LSHL
+#define OP_PT_SHR OP_LSHR
-#include "../../../mono-extensions/mono/mini/mini-native-types.c"
+#define OP_PT_DIV_UN OP_LDIV_UN
+#define OP_PT_REM_UN OP_LREM_UN
+#define OP_PT_SHR_UN OP_LSHR_UN
+
+#define OP_PT_ADD_IMM OP_LADD_IMM
+#define OP_PT_SUB_IMM OP_LSUB_IMM
+
+#define OP_PT_STORE_FP_MEMBASE_REG OP_STORER8_MEMBASE_REG
+
+#define OP_PCOMPARE OP_LCOMPARE
#else
+#define OP_PT_ADD OP_IADD
+#define OP_PT_SUB OP_ISUB
+#define OP_PT_MUL OP_IMUL
+#define OP_PT_DIV OP_IDIV
+#define OP_PT_REM OP_IREM
+#define OP_PT_NEG OP_INEG
+#define OP_PT_AND OP_IAND
+#define OP_PT_OR OP_IOR
+#define OP_PT_XOR OP_IXOR
+#define OP_PT_NOT OP_INOT
+#define OP_PT_SHL OP_ISHL
+#define OP_PT_SHR OP_ISHR
-#include "mini.h"
+#define OP_PT_DIV_UN OP_IDIV_UN
+#define OP_PT_REM_UN OP_IREM_UN
+#define OP_PT_SHR_UN OP_ISHR_UN
-MonoType*
-mini_native_type_replace_type (MonoType *type)
+#define OP_PT_ADD_IMM OP_IADD_IMM
+#define OP_PT_SUB_IMM OP_ISUB_IMM
+
+#define OP_PT_STORE_FP_MEMBASE_REG OP_STORER4_MEMBASE_REG
+
+#define OP_PCOMPARE OP_ICOMPARE
+
+#endif
+
+static const IntIntrisic int_binop[] = {
+ { "op_Addition", { OP_PT_ADD, OP_PT_ADD, OP_FADD, OP_RADD } },
+ { "op_Subtraction", { OP_PT_SUB, OP_PT_SUB, OP_FSUB, OP_RSUB } },
+ { "op_Multiply", { OP_PT_MUL, OP_PT_MUL, OP_FMUL, OP_RMUL } },
+ { "op_Division", { OP_PT_DIV, OP_PT_DIV_UN, OP_FDIV, OP_RDIV } },
+ { "op_Modulus", { OP_PT_REM, OP_PT_REM_UN, OP_FREM, OP_RREM } },
+ { "op_BitwiseAnd", { OP_PT_AND, OP_PT_AND } },
+ { "op_BitwiseOr", { OP_PT_OR, OP_PT_OR } },
+ { "op_ExclusiveOr", { OP_PT_XOR, OP_PT_XOR } },
+ { "op_LeftShift", { OP_PT_SHL, OP_PT_SHL } },
+ { "op_RightShift", { OP_PT_SHR, OP_PT_SHR_UN } },
+};
+
+static const IntIntrisic int_unnop[] = {
+ { "op_UnaryPlus", { OP_MOVE, OP_MOVE, OP_FMOVE, OP_RMOVE } },
+ { "op_UnaryNegation", { OP_PT_NEG, OP_PT_NEG, OP_FNEG, OP_RNEG } },
+ { "op_OnesComplement", { OP_PT_NOT, OP_PT_NOT, OP_FNOT, OP_RNOT } },
+};
+
+static const IntIntrisic int_cmpop[] = {
+ { "op_Inequality", { OP_ICNEQ, OP_ICNEQ, OP_FCNEQ, OP_RCNEQ } },
+ { "op_Equality", { OP_ICEQ, OP_ICEQ, OP_FCEQ, OP_RCEQ } },
+ { "op_GreaterThan", { OP_ICGT, OP_ICGT_UN, OP_FCGT, OP_RCGT } },
+ { "op_GreaterThanOrEqual", { OP_ICGE, OP_ICGE_UN, OP_FCGE, OP_RCGE } },
+ { "op_LessThan", { OP_ICLT, OP_ICLT_UN, OP_FCLT, OP_RCLT } },
+ { "op_LessThanOrEqual", { OP_ICLE, OP_ICLE_UN, OP_FCLE, OP_RCLE } },
+};
+
+static const MagicTypeInfo type_info[] = {
+ //nint
+ { 0, STACK_I8, STACK_I4, STACK_PTR, OP_ICONV_TO_I8, OP_LCONV_TO_I4, OP_MOVE, OP_PT_ADD_IMM, OP_PT_SUB_IMM, OP_STORE_MEMBASE_REG, OP_PCOMPARE },
+ //nuint
+ { 1, STACK_I8, STACK_I4, STACK_PTR, OP_ICONV_TO_U8, OP_LCONV_TO_U4, OP_MOVE, OP_PT_ADD_IMM, OP_PT_SUB_IMM, OP_STORE_MEMBASE_REG, OP_PCOMPARE },
+ //nfloat
+ { 2, STACK_R8, STACK_R8, STACK_R8, OP_FCONV_TO_R8, OP_FCONV_TO_R4, OP_FMOVE, 0, 0, OP_PT_STORE_FP_MEMBASE_REG, 0 },
+};
+
+static inline gboolean mono_class_is_magic_int (MonoClass *klass);
+static inline gboolean mono_class_is_magic_float (MonoClass *klass);
+
+
+static inline gboolean
+type_size (MonoCompile *cfg, MonoType *type)
{
- return type;
+ if (type->type == MONO_TYPE_I4 || type->type == MONO_TYPE_U4)
+ return 4;
+ else if (type->type == MONO_TYPE_I8 || type->type == MONO_TYPE_U8)
+ return 8;
+ else if (type->type == MONO_TYPE_R4 && !type->byref && cfg->r4fp)
+ return 4;
+ else if (type->type == MONO_TYPE_R8 && !type->byref)
+ return 8;
+ return SIZEOF_VOID_P;
}
+#ifndef DISABLE_JIT
+
+static gboolean is_int_type (MonoType *t);
+static gboolean is_float_type (MonoType *t);
+
+static MonoInst*
+emit_narrow (MonoCompile *cfg, const MagicTypeInfo *info, int sreg)
+{
+ MonoInst *ins;
+
+ MONO_INST_NEW (cfg, ins, info->conv_8_to_4);
+ ins->sreg1 = sreg;
+ if (info->conv_8_to_4 == OP_FCONV_TO_R4)
+ ins->type = cfg->r4_stack_type;
+ else
+ ins->type = info->small_stack_type;
+ ins->dreg = alloc_dreg (cfg, ins->type);
+ MONO_ADD_INS (cfg->cbb, ins);
+ return mono_decompose_opcode (cfg, ins);
+}
+
+static MonoInst*
+emit_widen (MonoCompile *cfg, const MagicTypeInfo *info, int sreg)
+{
+ MonoInst *ins;
+
+ if (cfg->r4fp && info->conv_4_to_8 == OP_FCONV_TO_R8)
+ MONO_INST_NEW (cfg, ins, OP_RCONV_TO_R8);
+ else
+ MONO_INST_NEW (cfg, ins, info->conv_4_to_8);
+ ins->sreg1 = sreg;
+ ins->type = info->big_stack_type;
+ ins->dreg = alloc_dreg (cfg, info->big_stack_type);
+ MONO_ADD_INS (cfg->cbb, ins);
+ return mono_decompose_opcode (cfg, ins);
+}
+
+static MonoInst*
+emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args, const MagicTypeInfo *info)
+{
+ int i = 0;
+ const char *name = cmethod->name;
+ MonoInst *ins;
+ int type_index, stack_type;
+
+ if (info->op_index == 2 && cfg->r4fp && SIZEOF_VOID_P == 4) {
+ type_index = 3;
+ stack_type = STACK_R4;
+ } else {
+ type_index = info->op_index;
+ stack_type = info->stack_type;
+ }
+
+ if (!strcmp ("op_Implicit", name) || !strcmp ("op_Explicit", name)) {
+ int source_size = type_size (cfg, fsig->params [0]);
+ int dest_size = type_size (cfg, fsig->ret);
+
+ switch (info->big_stack_type) {
+ case STACK_I8:
+ if (!is_int_type (fsig->params [0]) || !is_int_type (fsig->ret))
+ return NULL;
+ break;
+ case STACK_R8:
+ if (!is_float_type (fsig->params [0]) || !is_float_type (fsig->ret))
+ return NULL;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ //4 -> 4 or 8 -> 8
+ if (source_size == dest_size)
+ return args [0];
+
+ //4 -> 8
+ if (source_size < dest_size)
+ return emit_widen (cfg, info, args [0]->dreg);
+
+ //8 -> 4
+ return emit_narrow (cfg, info, args [0]->dreg);
+ }
+
+ if (!strcmp (".ctor", name)) {
+ gboolean is_ldaddr = args [0]->opcode == OP_LDADDR;
+ int arg0 = args [1]->dreg;
+ int arg_size = type_size (cfg, fsig->params [0]);
+
+ if (arg_size > SIZEOF_VOID_P) //8 -> 4
+ arg0 = emit_narrow (cfg, info, arg0)->dreg;
+ else if (arg_size < SIZEOF_VOID_P) //4 -> 8
+ arg0 = emit_widen (cfg, info, arg0)->dreg;
+
+ if (is_ldaddr) { /*Eliminate LDADDR if it's initing a local var*/
+ int dreg = ((MonoInst*)args [0]->inst_p0)->dreg;
+ NULLIFY_INS (args [0]);
+ EMIT_NEW_UNALU (cfg, ins, info->move, dreg, arg0);
+ cfg->has_indirection = TRUE;
+ } else {
+ EMIT_NEW_STORE_MEMBASE (cfg, ins, info->store_op, args [0]->dreg, 0, arg0);
+ }
+ return ins;
+ }
+
+ if (!strcmp ("op_Increment", name) || !strcmp ("op_Decrement", name)) {
+ gboolean inc = !strcmp ("op_Increment", name);
+ /* FIXME float inc is too complex to bother with*/
+ //this is broken with ints too
+ // if (!info->inc_op)
+ return NULL;
+
+ /* We have IR for inc/dec */
+ MONO_INST_NEW (cfg, ins, inc ? info->inc_op : info->dec_op);
+ ins->dreg = alloc_dreg (cfg, info->stack_type);
+ ins->sreg1 = args [0]->dreg;
+ ins->inst_imm = 1;
+ ins->type = info->stack_type;
+ MONO_ADD_INS (cfg->cbb, ins);
+ return ins;
+ }
+
+ for (i = 0; i < sizeof (int_binop) / sizeof (IntIntrisic); ++i) {
+ if (!strcmp (int_binop [i].op_name, name)) {
+ if (!int_binop [i].op_table [info->op_index])
+ return NULL;
+ g_assert (int_binop [i].op_table [type_index]);
+
+ MONO_INST_NEW (cfg, ins, int_binop [i].op_table [type_index]);
+ ins->dreg = alloc_dreg (cfg, stack_type);
+ ins->sreg1 = args [0]->dreg;
+ ins->sreg2 = args [1]->dreg;
+ ins->type = stack_type;
+ MONO_ADD_INS (cfg->cbb, ins);
+ return mono_decompose_opcode (cfg, ins);
+ }
+ }
+
+ for (i = 0; i < sizeof (int_unnop) / sizeof (IntIntrisic); ++i) {
+ if (!strcmp (int_unnop [i].op_name, name)) {
+ g_assert (int_unnop [i].op_table [type_index]);
+
+ MONO_INST_NEW (cfg, ins, int_unnop [i].op_table [type_index]);
+ ins->dreg = alloc_dreg (cfg, stack_type);
+ ins->sreg1 = args [0]->dreg;
+ ins->type = stack_type;
+ MONO_ADD_INS (cfg->cbb, ins);
+ return ins;
+ }
+ }
+
+ for (i = 0; i < sizeof (int_cmpop) / sizeof (IntIntrisic); ++i) {
+ if (!strcmp (int_cmpop [i].op_name, name)) {
+ g_assert (int_cmpop [i].op_table [type_index]);
+
+ if (info->compare_op) {
+ MONO_INST_NEW (cfg, ins, info->compare_op);
+ ins->dreg = -1;
+ ins->sreg1 = args [0]->dreg;
+ ins->sreg2 = args [1]->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ MONO_INST_NEW (cfg, ins, int_cmpop [i].op_table [type_index]);
+ ins->dreg = alloc_preg (cfg);
+ ins->type = STACK_I4;
+ MONO_ADD_INS (cfg->cbb, ins);
+ } else {
+ MONO_INST_NEW (cfg, ins, int_cmpop [i].op_table [type_index]);
+ ins->dreg = alloc_ireg (cfg);
+ ins->sreg1 = args [0]->dreg;
+ ins->sreg2 = args [1]->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
+
+ return ins;
+ }
+ }
+
+ return NULL;
+}
+
+
MonoInst*
mono_emit_native_types_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
+ if (mono_class_is_magic_int (cmethod->klass)) {
+ const char *class_name = cmethod->klass->name;
+ if (!strcmp ("nint", class_name))
+ return emit_intrinsics (cfg, cmethod, fsig, args, &type_info [0]);
+ else
+ return emit_intrinsics (cfg, cmethod, fsig, args, &type_info [1]);
+ } else if (mono_class_is_magic_float (cmethod->klass))
+ return emit_intrinsics (cfg, cmethod, fsig, args, &type_info [2]);
+
return NULL;
}
+#endif /* !DISABLE_JIT */
+
+static inline gboolean
+mono_class_is_magic_assembly (MonoClass *klass)
+{
+ if (!klass->image->assembly_name)
+ return FALSE;
+ if (!strcmp ("Xamarin.iOS", klass->image->assembly_name))
+ return TRUE;
+ if (!strcmp ("Xamarin.Mac", klass->image->assembly_name))
+ return TRUE;
+ return FALSE;
+}
+
+static inline gboolean
+mono_class_is_magic_int (MonoClass *klass)
+{
+ static MonoClass *magic_nint_class;
+ static MonoClass *magic_nuint_class;
+
+ if (klass == magic_nint_class)
+ return TRUE;
+
+ if (klass == magic_nuint_class)
+ return TRUE;
+
+ if (magic_nint_class && magic_nuint_class)
+ return FALSE;
+
+ if (!mono_class_is_magic_assembly (klass))
+ return FALSE;
+
+ if (strcmp ("System", klass->name_space) != 0)
+ return FALSE;
+
+ if (strcmp ("nint", klass->name) == 0) {
+ magic_nint_class = klass;
+ return TRUE;
+ }
+
+ if (strcmp ("nuint", klass->name) == 0){
+ magic_nuint_class = klass;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static inline gboolean
+mono_class_is_magic_float (MonoClass *klass)
+{
+ static MonoClass *magic_nfloat_class;
+
+ if (klass == magic_nfloat_class)
+ return TRUE;
+
+ if (magic_nfloat_class)
+ return FALSE;
+
+ if (!mono_class_is_magic_assembly (klass))
+ return FALSE;
+
+ if (strcmp ("System", klass->name_space) != 0)
+ return FALSE;
+
+ if (strcmp ("nfloat", klass->name) == 0) {
+ magic_nfloat_class = klass;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+is_int_type (MonoType *t)
+{
+ if (t->type != MONO_TYPE_I4 && t->type != MONO_TYPE_I8 && t->type != MONO_TYPE_U4 && t->type != MONO_TYPE_U8 && !mono_class_is_magic_int (mono_class_from_mono_type (t)))
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+is_float_type (MonoType *t)
+{
+ if (t->type != MONO_TYPE_R4 && t->type != MONO_TYPE_R8 && !mono_class_is_magic_float (mono_class_from_mono_type (t)))
+ return FALSE;
+ return TRUE;
+}
+
+MonoType*
+mini_native_type_replace_type (MonoType *type)
+{
+ MonoClass *klass;
+
+ if (type->type != MONO_TYPE_VALUETYPE)
+ return type;
+ klass = type->data.klass;
+
+ if (mono_class_is_magic_int (klass))
+ return type->byref ? &mono_defaults.int_class->this_arg : &mono_defaults.int_class->byval_arg;
+ if (mono_class_is_magic_float (klass))
+#if SIZEOF_VOID_P == 8
+ return type->byref ? &mono_defaults.double_class->this_arg : &mono_defaults.double_class->byval_arg;
+#else
+ return type->byref ? &mono_defaults.single_class->this_arg : &mono_defaults.single_class->byval_arg;
#endif
+ return type;
+}
* Copyright 2003 Ximian, Inc
* Copyright 2003-2011 Novell Inc
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
MINI_OP(OP_LOAD, "load", NONE, NONE, NONE)
MINI_OP(OP_LDADDR, "ldaddr", IREG, NONE, NONE)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*
* See LICENSE for licensing information.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <signal.h>
+
/*
* mini-runtime.c: Runtime code for the JIT
*
* Copyright 2002-2003 Ximian, Inc.
* Copyright 2003-2010 Novell, Inc.
* Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
MonoVTable *vtable;
mono_jit_stats.methods_lookups++;
- vtable = mono_class_vtable (domain, method->klass);
+ vtable = mono_class_vtable_full (domain, method->klass, error);
+ if (!is_ok (error))
+ return NULL;
g_assert (vtable);
if (!mono_runtime_class_init_full (vtable, error))
return NULL;
if (!info->dyn_call_info) {
if (mono_llvm_only) {
-#ifndef ENABLE_GSHAREDVT
+#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
g_assert_not_reached ();
#endif
info->gsharedvt_invoke = TRUE;
mono_error_set_exception_instance (error, (MonoException*) *exc);
if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
- return mono_value_box (domain, info->ret_box_class, retval);
+ return mono_value_box_checked (domain, info->ret_box_class, retval, error);
else
return *(MonoObject**)retval;
}
mono_arch_finish_dyn_call (info->dyn_call_info, buf);
if (info->ret_box_class)
- return mono_value_box (domain, info->ret_box_class, retval);
+ return mono_value_box_checked (domain, info->ret_box_class, retval, error);
else
return *(MonoObject**)retval;
}
* (C) 2003 Ximian, Inc.
* (C) 2003-2011 Novell, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <glib.h>
return res;
}
-/*
- * Precompute data to speed up mono_delegate_trampoline ().
- * METHOD might be NULL.
- */
-static MonoDelegateTrampInfo*
-create_delegate_trampoline_data (MonoDomain *domain, MonoClass *klass, MonoMethod *method)
-{
- MonoDelegateTrampInfo *tramp_data;
- MonoMethod *invoke;
- MonoError err;
-
- // Precompute the delegate invoke impl and pass it to the delegate trampoline
- invoke = mono_get_delegate_invoke (klass);
- g_assert (invoke);
-
- tramp_data = (MonoDelegateTrampInfo *)mono_domain_alloc0 (domain, sizeof (MonoDelegateTrampInfo));
- tramp_data->invoke = invoke;
- tramp_data->invoke_sig = mono_method_signature (invoke);
- tramp_data->impl_this = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
- tramp_data->impl_nothis = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
- tramp_data->method = method;
- if (method) {
- mono_error_init (&err);
- tramp_data->sig = mono_method_signature_checked (method, &err);
- tramp_data->need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (method, FALSE);
- }
-
- return tramp_data;
-}
-
/**
* mono_delegate_trampoline:
*
/*
* mono_create_delegate_trampoline_info:
*
- * Create a delegate trampoline for the KLASS+METHOD pair.
+ * Create a trampoline info structure for the KLASS+METHOD pair.
*/
MonoDelegateTrampInfo*
mono_create_delegate_trampoline_info (MonoDomain *domain, MonoClass *klass, MonoMethod *method)
{
+ MonoMethod *invoke;
+ MonoError error;
MonoDelegateTrampInfo *tramp_info;
MonoClassMethodPair pair, *dpair;
guint32 code_size = 0;
if (tramp_info)
return tramp_info;
- tramp_info = create_delegate_trampoline_data (domain, klass, method);
+ invoke = mono_get_delegate_invoke (klass);
+ g_assert (invoke);
+ tramp_info = (MonoDelegateTrampInfo *)mono_domain_alloc0 (domain, sizeof (MonoDelegateTrampInfo));
+ tramp_info->invoke = invoke;
+ tramp_info->invoke_sig = mono_method_signature (invoke);
+ tramp_info->impl_this = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
+ tramp_info->impl_nothis = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
+ tramp_info->method = method;
+ if (method) {
+ mono_error_init (&error);
+ tramp_info->sig = mono_method_signature_checked (method, &error);
+ tramp_info->need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (method, FALSE);
+ }
tramp_info->invoke_impl = mono_create_specific_trampoline (tramp_info, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
g_assert (code_size);
* Copyright 2003-2008 Ximian, Inc.
*
* See LICENSE for licensing information.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <signal.h>
--- /dev/null
+/*
+ * mini-x86-gsharedvt.c: gsharedvt support code for x86
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ *
+ * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include "mini.h"
+
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+/*
+ * GSHAREDVT
+ */
+
+gboolean
+mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
+{
+ /*
+ if (sig->ret && is_variable_size (sig->ret))
+ return FALSE;
+ */
+ return TRUE;
+}
+
+/*
+ * mono_arch_get_gsharedvt_call_info:
+ *
+ * Compute calling convention information for marshalling a call between NORMAL_SIG and GSHAREDVT_SIG.
+ * If GSHAREDVT_IN is TRUE, then the caller calls using the signature NORMAL_SIG but the call is received by
+ * a method with signature GSHAREDVT_SIG, otherwise its the other way around.
+ */
+gpointer
+mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
+{
+ GSharedVtCallInfo *info;
+ CallInfo *caller_cinfo, *callee_cinfo;
+ MonoMethodSignature *caller_sig, *callee_sig;
+ int i, j;
+ gboolean var_ret = FALSE;
+ CallInfo *cinfo, *gcinfo;
+ MonoMethodSignature *sig, *gsig;
+ GPtrArray *map;
+
+ if (gsharedvt_in) {
+ caller_sig = normal_sig;
+ callee_sig = gsharedvt_sig;
+ caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+ callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+ } else {
+ callee_sig = normal_sig;
+ callee_cinfo = mono_arch_get_call_info (NULL, callee_sig);
+ caller_sig = gsharedvt_sig;
+ caller_cinfo = mono_arch_get_call_info (NULL, caller_sig);
+ }
+
+ /*
+ * If GSHAREDVT_IN is true, this means we are transitioning from normal to gsharedvt code. The caller uses the
+ * normal call signature, while the callee uses the gsharedvt signature.
+ * If GSHAREDVT_IN is false, its the other way around.
+ */
+
+ /* sig/cinfo describes the normal call, while gsig/gcinfo describes the gsharedvt call */
+ if (gsharedvt_in) {
+ sig = caller_sig;
+ gsig = callee_sig;
+ cinfo = caller_cinfo;
+ gcinfo = callee_cinfo;
+ } else {
+ sig = callee_sig;
+ gsig = caller_sig;
+ cinfo = callee_cinfo;
+ gcinfo = caller_cinfo;
+ }
+
+ if (gcinfo->vtype_retaddr && gsig->ret && mini_is_gsharedvt_type (gsig->ret)) {
+ /*
+ * The return type is gsharedvt
+ */
+ var_ret = TRUE;
+ }
+
+ /*
+ * The stack looks like this:
+ * <arguments>
+ * <ret addr>
+ * <saved ebp>
+ * <call area>
+ * We have to map the stack slots in <arguments> to the stack slots in <call area>.
+ */
+ map = g_ptr_array_new ();
+
+ if (cinfo->vtype_retaddr) {
+ /*
+ * Map ret arg.
+ * This handles the case when the method returns a normal vtype, and when it returns a type arg, and its instantiated
+ * with a vtype.
+ */
+ g_ptr_array_add (map, GUINT_TO_POINTER (caller_cinfo->vret_arg_offset / sizeof (gpointer)));
+ g_ptr_array_add (map, GUINT_TO_POINTER (callee_cinfo->vret_arg_offset / sizeof (gpointer)));
+ }
+
+ for (i = 0; i < cinfo->nargs; ++i) {
+ ArgInfo *ainfo = &caller_cinfo->args [i];
+ ArgInfo *ainfo2 = &callee_cinfo->args [i];
+ int nslots;
+
+ switch (ainfo->storage) {
+ case ArgGSharedVt:
+ if (ainfo2->storage == ArgOnStack) {
+ nslots = callee_cinfo->args [i].nslots;
+ if (!nslots)
+ nslots = 1;
+ g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (gpointer)) + (1 << 16) + (nslots << 18)));
+ g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (gpointer))));
+ } else {
+ g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (gpointer))));
+ g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (gpointer))));
+ }
+ break;
+ default:
+ if (ainfo2->storage == ArgOnStack) {
+ nslots = cinfo->args [i].nslots;
+ if (!nslots)
+ nslots = 1;
+ for (j = 0; j < nslots; ++j) {
+ g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (gpointer)) + j));
+ g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (gpointer)) + j));
+ }
+ } else {
+ g_assert (ainfo2->storage == ArgGSharedVt);
+ g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo->offset / sizeof (gpointer)) + (2 << 16)));
+ g_ptr_array_add (map, GUINT_TO_POINTER ((ainfo2->offset / sizeof (gpointer))));
+ }
+ break;
+ }
+ }
+
+ info = mono_domain_alloc0 (mono_domain_get (), sizeof (GSharedVtCallInfo) + (map->len * sizeof (int)));
+ info->addr = addr;
+ info->stack_usage = callee_cinfo->stack_usage;
+ info->ret_marshal = GSHAREDVT_RET_NONE;
+ info->gsharedvt_in = gsharedvt_in ? 1 : 0;
+ info->vret_slot = -1;
+ info->calli = calli ? 1 : 0;
+ if (var_ret)
+ info->vret_arg_slot = gcinfo->vret_arg_offset / sizeof (gpointer);
+ else
+ info->vret_arg_slot = -1;
+ info->vcall_offset = vcall_offset;
+ info->map_count = map->len / 2;
+ for (i = 0; i < map->len; ++i)
+ info->map [i] = GPOINTER_TO_UINT (g_ptr_array_index (map, i));
+ g_ptr_array_free (map, TRUE);
+
+ /* Compute return value marshalling */
+ if (var_ret) {
+ switch (cinfo->ret.storage) {
+ case ArgInIReg:
+ if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I1)
+ info->ret_marshal = GSHAREDVT_RET_I1;
+ else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U1 || sig->ret->type == MONO_TYPE_BOOLEAN))
+ info->ret_marshal = GSHAREDVT_RET_U1;
+ else if (gsharedvt_in && !sig->ret->byref && sig->ret->type == MONO_TYPE_I2)
+ info->ret_marshal = GSHAREDVT_RET_I2;
+ else if (gsharedvt_in && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U2 || sig->ret->type == MONO_TYPE_CHAR))
+ info->ret_marshal = GSHAREDVT_RET_U2;
+ else if (cinfo->ret.is_pair)
+ info->ret_marshal = GSHAREDVT_RET_IREGS;
+ else
+ info->ret_marshal = GSHAREDVT_RET_IREG;
+ break;
+ case ArgOnDoubleFpStack:
+ info->ret_marshal = GSHAREDVT_RET_DOUBLE_FPSTACK;
+ break;
+ case ArgOnFloatFpStack:
+ info->ret_marshal = GSHAREDVT_RET_FLOAT_FPSTACK;
+ break;
+ case ArgOnStack:
+ /* The caller passes in a vtype ret arg as well */
+ g_assert (gcinfo->vtype_retaddr);
+ /* Just have to pop the arg, as done by normal methods in their epilog */
+ info->ret_marshal = GSHAREDVT_RET_STACK_POP;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ } else if (gsharedvt_in && cinfo->vtype_retaddr) {
+ info->ret_marshal = GSHAREDVT_RET_STACK_POP;
+ }
+
+ if (gsharedvt_in && var_ret && !caller_cinfo->vtype_retaddr) {
+ /* Allocate stack space for the return value */
+ info->vret_slot = info->stack_usage / sizeof (gpointer);
+ // FIXME:
+ info->stack_usage += sizeof (gpointer) * 3;
+ }
+
+ info->stack_usage = ALIGN_TO (info->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
+
+ g_free (caller_cinfo);
+ g_free (callee_cinfo);
+
+ return info;
+}
+#endif
* Copyright 2003 Ximian, Inc.
* Copyright 2003-2011 Novell Inc.
* Copyright 2011 Xamarin Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
#include <string.h>
x86_patch (code, (unsigned char*)target);
}
-typedef enum {
- ArgInIReg,
- ArgInFloatSSEReg,
- ArgInDoubleSSEReg,
- ArgOnStack,
- ArgValuetypeInReg,
- ArgOnFloatFpStack,
- ArgOnDoubleFpStack,
- /* gsharedvt argument passed by addr */
- ArgGSharedVt,
- ArgNone
-} ArgStorage;
-
-typedef struct {
- gint16 offset;
- gint8 reg;
- ArgStorage storage;
- int nslots;
- gboolean is_pair;
-
- /* Only if storage == ArgValuetypeInReg */
- ArgStorage pair_storage [2];
- gint8 pair_regs [2];
-} ArgInfo;
-
-typedef struct {
- int nargs;
- guint32 stack_usage;
- guint32 reg_usage;
- guint32 freg_usage;
- gboolean need_stack_align;
- guint32 stack_align_amount;
- gboolean vtype_retaddr;
- /* The index of the vret arg in the argument list */
- int vret_arg_index;
- int vret_arg_offset;
- /* Argument space popped by the callee */
- int callee_stack_pop;
- ArgInfo ret;
- ArgInfo sig_cookie;
- ArgInfo args [1];
-} CallInfo;
-
#define FLOAT_PARAM_REGS 0
static const guint32 thiscall_param_regs [] = { X86_ECX, X86_NREG };
mono_aot_register_jit_icall ("mono_x86_throw_exception", mono_x86_throw_exception);
mono_aot_register_jit_icall ("mono_x86_throw_corlib_exception", mono_x86_throw_corlib_exception);
-#if defined(ENABLE_GSHAREDVT)
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
mono_aot_register_jit_icall ("mono_x86_start_gsharedvt_call", mono_x86_start_gsharedvt_call);
#endif
}
return code;
}
-#define REAL_PRINT_REG(text,reg) \
-mono_assert (reg >= 0); \
-x86_push_reg (code, X86_EAX); \
-x86_push_reg (code, X86_EDX); \
-x86_push_reg (code, X86_ECX); \
-x86_push_reg (code, reg); \
-x86_push_imm (code, reg); \
-x86_push_imm (code, text " %d %p\n"); \
-x86_mov_reg_imm (code, X86_EAX, printf); \
-x86_call_reg (code, X86_EAX); \
-x86_alu_reg_imm (code, X86_ADD, X86_ESP, 3*4); \
-x86_pop_reg (code, X86_ECX); \
-x86_pop_reg (code, X86_EDX); \
-x86_pop_reg (code, X86_EAX);
-
-/* REAL_PRINT_REG does not appear to be used, and was not adapted to work with Native Client. */
-#ifdef __native__client_codegen__
-#define REAL_PRINT_REG(text, reg) g_assert_not_reached()
-#endif
-
/* benchmark and set based on cpu */
#define LOOP_ALIGNMENT 8
#define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
}
}
-#if defined(ENABLE_GSHAREDVT)
-
-#include "../../../mono-extensions/mono/mini/mini-x86-gsharedvt.c"
-
-#endif /* !MONOTOUCH */
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+ return get_call_info (mp, sig);
+}
int map [MONO_ZERO_LEN_ARRAY];
} GSharedVtCallInfo;
+typedef enum {
+ ArgInIReg,
+ ArgInFloatSSEReg,
+ ArgInDoubleSSEReg,
+ ArgOnStack,
+ ArgValuetypeInReg,
+ ArgOnFloatFpStack,
+ ArgOnDoubleFpStack,
+ /* gsharedvt argument passed by addr */
+ ArgGSharedVt,
+ ArgNone
+} ArgStorage;
+
+typedef struct {
+ gint16 offset;
+ gint8 reg;
+ ArgStorage storage;
+ int nslots;
+ gboolean is_pair;
+
+ /* Only if storage == ArgValuetypeInReg */
+ ArgStorage pair_storage [2];
+ gint8 pair_regs [2];
+} ArgInfo;
+
+typedef struct {
+ int nargs;
+ guint32 stack_usage;
+ guint32 reg_usage;
+ guint32 freg_usage;
+ gboolean need_stack_align;
+ guint32 stack_align_amount;
+ gboolean vtype_retaddr;
+ /* The index of the vret arg in the argument list */
+ int vret_arg_index;
+ int vret_arg_offset;
+ /* Argument space popped by the callee */
+ int callee_stack_pop;
+ ArgInfo ret;
+ ArgInfo sig_cookie;
+ ArgInfo args [1];
+} CallInfo;
+
guint8*
mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset);
gpointer
mono_x86_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg);
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);
+
#endif /* __MONO_MINI_X86_H__ */
* Copyright 2002-2003 Ximian, Inc.
* Copyright 2003-2010 Novell, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Copyright 2002-2003 Ximian Inc
* Copyright 2003-2011 Novell Inc
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_MINI_H__
#define __MONO_MINI_H__
gboolean
mini_class_is_generic_sharable (MonoClass *klass);
+
+gboolean
+mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars, gboolean allow_partial);
+
gboolean
mono_is_partially_sharable_inst (MonoGenericInst *inst);
#define ARCH_VARARG_ICALLS 0
#endif
+/*
+ * Native unwinder integration
+ */
+void mono_exception_native_unwind (void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info);
+
+
#endif /* __MONO_MINI_H__ */
* Marcos Henrich (marcos.henrich@xamarin.com)
*
* Copyright 2014 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
/*
* Copyright 2014 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SEQ_POINTS_H__
*
* (C) 2003 Ximian, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <string.h>
*
* (C) 2002 Ximian, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
--- /dev/null
+/*
+ * tramp-amd64-gsharedvt.c: libcorkscrew-based native unwinder
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ * Rodrigo Kumpera <kumpera@gmail.com>
+ * Andi McClure <andi.mcclure@xamarin.com>
+ *
+ * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/abi-details.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
+#include <mono/metadata/tabledefs.h>
+#include <mono/metadata/mono-debug-debugger.h>
+#include <mono/metadata/profiler-private.h>
+#include <mono/metadata/gc-internals.h>
+#include <mono/arch/amd64/amd64-codegen.h>
+
+#include <mono/utils/memcheck.h>
+
+#include "mini.h"
+#include "mini-amd64.h"
+#include "mini-amd64-gsharedvt.h"
+#include "debugger-agent.h"
+
+#if defined (MONO_ARCH_GSHAREDVT_SUPPORTED)
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+#define SRC_REG_SHIFT 0
+#define SRC_REG_MASK 0xFFFF
+
+#define SRC_DESCRIPTOR_MARSHAL_SHIFT 16
+#define SRC_DESCRIPTOR_MARSHAL_MASK 0x0FF
+
+#define SLOT_COUNT_SHIFT 24
+#define SLOT_COUNT_MASK 0xFF
+
+gpointer
+mono_amd64_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
+{
+ int i;
+
+#ifdef DEBUG_AMD64_GSHAREDVT
+ printf ("mono_amd64_start_gsharedvt_call info %p caller %p callee %p ctx %p\n", info, caller, callee, mrgctx_reg);
+
+ for (i = 0; i < PARAM_REGS; ++i)
+ printf ("\treg [%d] -> %p\n", i, caller [i]);
+#endif
+
+ /* Set vtype ret arg */
+ if (info->vret_slot != -1) {
+ DEBUG_AMD64_GSHAREDVT_PRINT ("vret handling\n[%d] < &%d (%p)\n", info->vret_arg_reg, info->vret_slot, &callee [info->vret_slot]);
+ g_assert (info->vret_slot);
+ callee [info->vret_arg_reg] = &callee [info->vret_slot];
+ }
+
+ for (i = 0; i < info->map_count; ++i) {
+ int src = info->map [i * 2];
+ int dst = info->map [(i * 2) + 1];
+ int arg_marshal = (src >> SRC_DESCRIPTOR_MARSHAL_SHIFT) & SRC_DESCRIPTOR_MARSHAL_MASK;
+
+ int source_reg = src & SRC_REG_MASK;
+ int dest_reg = dst & SRC_REG_MASK;
+
+ DEBUG_AMD64_GSHAREDVT_PRINT ("source %x dest %x marshal %d: ", src, dst, arg_marshal);
+ switch (arg_marshal) {
+ case GSHAREDVT_ARG_NONE:
+ callee [dest_reg] = caller [source_reg];
+ DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- %d (%p) <- (%p)\n", dest_reg, source_reg, &callee [dest_reg], caller [source_reg]);
+ break;
+ case GSHAREDVT_ARG_BYVAL_TO_BYREF:
+ /* gsharedvt argument passed by addr in reg/stack slot */
+ callee [dest_reg] = &caller [source_reg];
+ DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- &%d (%p) <- (%p)\n", dest_reg, source_reg, &callee [dest_reg], &caller [source_reg]);
+ break;
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL: {
+ int slot_count = (src >> SLOT_COUNT_SHIFT) & SLOT_COUNT_MASK;
+ int j;
+ gpointer *addr = caller [source_reg];
+
+ for (j = 0; j < slot_count; ++j)
+ callee [dest_reg + j] = addr [j];
+ DEBUG_AMD64_GSHAREDVT_PRINT ("[%d] <- [%d] (%d words) (%p) <- (%p)\n", dest_reg, source_reg, slot_count, &callee [dest_reg], &caller [source_reg]);
+ break;
+ }
+ default:
+ g_error ("cant handle arg marshal %d\n", arg_marshal);
+ }
+ }
+
+ //Can't handle for now
+ if (info->vcall_offset != -1){
+ MonoObject *this_obj = caller [0];
+
+ DEBUG_AMD64_GSHAREDVT_PRINT ("target is a vcall at offset %d\n", info->vcall_offset / 8);
+ if (G_UNLIKELY (!this_obj))
+ return NULL;
+ if (info->vcall_offset == MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET)
+ /* delegate invoke */
+ return ((MonoDelegate*)this_obj)->invoke_impl;
+ else
+ return *(gpointer*)((char*)this_obj->vtable + info->vcall_offset);
+ } else if (info->calli) {
+ /* The address to call is passed in the mrgctx reg */
+ return mrgctx_reg;
+ } else {
+ DEBUG_AMD64_GSHAREDVT_PRINT ("target is %p\n", info->addr);
+ return info->addr;
+ }
+}
+
+#ifndef DISABLE_JIT
+
+// Compiler support
+
+/*
+ * mono_arch_get_gsharedvt_arg_trampoline:
+ *
+ * See tramp-x86.c for documentation.
+ */
+gpointer
+mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
+{
+ guint8 *code, *start;
+ int buf_len;
+
+ buf_len = 32;
+
+ start = code = mono_domain_code_reserve (domain, buf_len);
+
+ amd64_mov_reg_imm (code, AMD64_RAX, arg);
+ amd64_jump_code (code, addr);
+ g_assert ((code - start) < buf_len);
+
+ nacl_domain_code_validate (domain, &start, buf_len, &code);
+ mono_arch_flush_icache (start, code - start);
+ mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
+
+ g_assert (0);
+ return start;
+}
+
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *code, *buf;
+ int buf_len, cfa_offset;
+ GSList *unwind_ops = NULL;
+ MonoJumpInfo *ji = NULL;
+ int n_arg_regs, n_arg_fregs, framesize, i;
+ int info_offset, offset, rgctx_arg_reg_offset;
+ int caller_reg_area_offset, callee_reg_area_offset, callee_stack_area_offset;
+ guint8 *br_out, *br [64], *br_ret [64];
+ int b_ret_index;
+ int reg_area_size;
+
+ buf_len = 2048;
+ buf = code = mono_global_codeman_reserve (buf_len);
+
+ /*
+ * We are being called by an gsharedvt arg trampoline, the info argument is in AMD64_RAX.
+ */
+ n_arg_regs = PARAM_REGS;
+ n_arg_fregs = FLOAT_PARAM_REGS;
+
+ /* Compute stack frame size and offsets */
+ offset = 0;
+ /* info reg */
+ info_offset = offset;
+ offset += 8;
+
+ /* rgctx reg */
+ rgctx_arg_reg_offset = offset;
+ offset += 8;
+
+ /*callconv in regs */
+ caller_reg_area_offset = offset;
+ reg_area_size = ALIGN_TO ((n_arg_regs + n_arg_fregs) * 8, MONO_ARCH_FRAME_ALIGNMENT);
+ offset += reg_area_size;
+
+ framesize = offset;
+
+ g_assert (framesize % MONO_ARCH_FRAME_ALIGNMENT == 0);
+ g_assert (reg_area_size % MONO_ARCH_FRAME_ALIGNMENT == 0);
+
+ /* unwind markers 1/3 */
+ cfa_offset = sizeof (gpointer);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RIP, -cfa_offset);
+
+ /* save the old frame pointer */
+ amd64_push_reg (code, AMD64_RBP);
+
+ /* unwind markers 2/3 */
+ cfa_offset += sizeof (gpointer);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RBP, - cfa_offset);
+
+ /* set it as the new frame pointer */
+ amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
+
+ /* unwind markers 3/3 */
+ mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
+
+ /* setup the frame */
+ amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
+
+ /* save stuff */
+
+ /* save info */
+ amd64_mov_membase_reg (code, AMD64_RSP, info_offset, AMD64_RAX, sizeof (mgreg_t));
+ /* save rgctx */
+ amd64_mov_membase_reg (code, AMD64_RSP, rgctx_arg_reg_offset, MONO_ARCH_RGCTX_REG, sizeof (mgreg_t));
+
+ for (i = 0; i < n_arg_regs; ++i)
+ amd64_mov_membase_reg (code, AMD64_RSP, caller_reg_area_offset + i * 8, param_regs [i], sizeof (mgreg_t));
+
+ for (i = 0; i < n_arg_fregs; ++i)
+ amd64_sse_movsd_membase_reg (code, AMD64_RSP, caller_reg_area_offset + (i + n_arg_regs) * 8, i);
+
+ /* TODO Allocate stack area used to pass arguments to the method */
+
+
+ /* Allocate callee register area just below the caller area so it can be accessed from start_gsharedvt_call using negative offsets */
+ /* XXX figure out alignment */
+ callee_reg_area_offset = reg_area_size - ((n_arg_regs + n_arg_fregs) * 8); /* Ensure alignment */
+ callee_stack_area_offset = callee_reg_area_offset + reg_area_size;
+ amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, reg_area_size);
+
+ /* Allocate stack area used to pass arguments to the method */
+ amd64_mov_reg_membase (code, AMD64_R11, AMD64_RAX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage), 4);
+ amd64_alu_reg_reg (code, X86_SUB, AMD64_RSP, AMD64_R11);
+
+ /* The stack now looks like this:
+
+ <caller stack params area>
+ <return address>
+ <old frame pointer>
+ <caller registers area>
+ <rgctx>
+ <gsharedvt info>
+ <calee stack area>
+ <calee reg area>
+ */
+
+ /* Call start_gsharedvt_call () */
+ /* arg1 == info */
+ amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RAX, sizeof(mgreg_t));
+ /* arg2 = caller stack area */
+ amd64_lea_membase (code, MONO_AMD64_ARG_REG2, AMD64_RBP, -(framesize - caller_reg_area_offset));
+
+ /* arg3 == callee stack area */
+ amd64_lea_membase (code, MONO_AMD64_ARG_REG3, AMD64_RSP, callee_reg_area_offset);
+
+ /* arg4 = mrgctx reg */
+ amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG4, MONO_ARCH_RGCTX_REG, sizeof(mgreg_t));
+
+ if (aot) {
+ code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_start_gsharedvt_call");
+ amd64_call_reg (code, AMD64_R11);
+ } else {
+ g_error ("no aot");
+ }
+
+ /* Method to call is now on RAX. Restore regs and jump */
+ amd64_mov_reg_reg (code, AMD64_R11, AMD64_RAX, sizeof(mgreg_t));
+
+ for (i = 0; i < n_arg_regs; ++i)
+ amd64_mov_reg_membase (code, param_regs [i], AMD64_RSP, callee_reg_area_offset + i * 8, sizeof (mgreg_t));
+
+ for (i = 0; i < n_arg_fregs; ++i)
+ amd64_sse_movsd_reg_membase (code, i, AMD64_RSP, callee_reg_area_offset + (i + n_arg_regs) * 8);
+
+ //load rgctx
+ amd64_mov_reg_membase (code, MONO_ARCH_RGCTX_REG, AMD64_RBP, -(framesize - rgctx_arg_reg_offset), sizeof (mgreg_t));
+
+ /* Clear callee reg area */
+ amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, reg_area_size);
+
+ /* Call the thing */
+ amd64_call_reg (code, AMD64_R11);
+
+ /* Marshal return value. Available registers: R10 and R11 */
+ /* Load info struct */
+ amd64_mov_reg_membase (code, AMD64_R10, AMD64_RBP, -(framesize - info_offset), sizeof (mgreg_t));
+
+ /* Branch to the in/out handling code */
+ amd64_alu_membase_imm_size (code, X86_CMP, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in), 1, 4);
+
+ b_ret_index = 0;
+ br_out = code;
+ x86_branch32 (code, X86_CC_NE, 0, TRUE);
+
+ /*
+ * IN CASE
+ */
+
+ /* Load vret_slot */
+ amd64_mov_reg_membase (code, AMD64_RDI, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot), 4);
+ amd64_alu_reg_imm (code, X86_SUB, AMD64_RDI, n_arg_regs + n_arg_fregs);
+ amd64_shift_reg_imm (code, X86_SHL, AMD64_RDI, 3);
+
+ /* vret address is RBP - (framesize - caller_reg_area_offset) */
+ amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, sizeof(mgreg_t));
+ amd64_alu_reg_reg (code, X86_ADD, AMD64_R11, AMD64_RDI);
+
+ /* Load ret marshal type */
+ /* Load vret address in R11 */
+ amd64_mov_reg_membase (code, AMD64_R10, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal), 4);
+
+ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
+ amd64_alu_reg_imm (code, X86_CMP, AMD64_R10, i);
+ br [i] = code;
+ amd64_branch8 (code, X86_CC_EQ, 0, TRUE);
+ }
+ x86_breakpoint (code); /* unhandled case */
+
+ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
+ mono_amd64_patch (br [i], code);
+ switch (i) {
+ case GSHAREDVT_RET_NONE:
+ break;
+ case GSHAREDVT_RET_I1:
+ amd64_widen_membase (code, AMD64_RAX, AMD64_R11, 0, TRUE, FALSE);
+ break;
+ case GSHAREDVT_RET_U1:
+ amd64_widen_membase (code, AMD64_RAX, AMD64_R11, 0, FALSE, FALSE);
+ break;
+ case GSHAREDVT_RET_I2:
+ amd64_widen_membase (code, AMD64_RAX, AMD64_R11, 0, TRUE, TRUE);
+ break;
+ case GSHAREDVT_RET_U2:
+ amd64_widen_membase (code, AMD64_RAX, AMD64_R11, 0, FALSE, TRUE);
+ break;
+ case GSHAREDVT_RET_I4: // CORRECT
+ case GSHAREDVT_RET_U4: // THIS IS INCORRECT. WHY IS IT NOT FAILING?
+ amd64_movsxd_reg_membase (code, AMD64_RAX, AMD64_R11, 0);
+ break;
+ case GSHAREDVT_RET_I8:
+ amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 0, 8);
+ break;
+ case GSHAREDVT_RET_IREGS_1:
+ amd64_mov_reg_membase (code, return_regs [i - GSHAREDVT_RET_IREGS_1], AMD64_R11, 0, 8);
+ break;
+ case GSHAREDVT_RET_R8:
+ amd64_sse_movsd_reg_membase (code, AMD64_XMM0, AMD64_R11, 0);
+ break;
+ default:
+ x86_breakpoint (code); /* can't handle specific case */
+ }
+
+ br_ret [b_ret_index ++] = code;
+ x86_jump32 (code, 0);
+ }
+
+ /*
+ * OUT CASE
+ */
+ mono_amd64_patch (br_out, code);
+
+ /*
+ Address to write return to is in the original value of the register specified by vret_arg_reg.
+ This will be either RSI or RDI depending on whether this is a static call.
+ Its location:
+ We alloc 'framesize' bytes below RBP to save regs, info and rgctx. RSP = RBP - framesize
+ We store rdi at RSP + caller_reg_area_offset + slot_index_of (register) * 8.
+
+ address: RBP - framesize + caller_reg_area_offset + 8*slot
+ */
+
+ int caller_vret_offset = caller_reg_area_offset - framesize;
+
+ /* Load vret address in R11 */
+ /* Position to return to is passed as a hidden argument. Load 'vret_arg_slot' to find it */
+ amd64_movsxd_reg_membase (code, AMD64_R11, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_reg));
+
+ // In the GSHAREDVT_RET_NONE case, vret_arg_slot is -1. In this case, skip marshalling.
+ amd64_alu_reg_imm (code, X86_CMP, AMD64_R11, 0);
+ br_ret [b_ret_index ++] = code;
+ amd64_branch32 (code, X86_CC_LT, 0, TRUE);
+
+ /* Compute ret area address in the caller frame, *( ((gpointer *)RBP) [R11+2] ) */
+ amd64_shift_reg_imm (code, X86_SHL, AMD64_R11, 3);
+ amd64_alu_reg_imm (code, X86_ADD, AMD64_R11, caller_vret_offset);
+ amd64_alu_reg_reg (code, X86_ADD, AMD64_R11, AMD64_RBP);
+ amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, sizeof (gpointer));
+
+ /* Load ret marshal type in R10 */
+ amd64_mov_reg_membase (code, AMD64_R10, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal), 4);
+
+ // Switch table for ret_marshal value
+ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
+ amd64_alu_reg_imm (code, X86_CMP, AMD64_R10, i);
+ br [i] = code;
+ amd64_branch8 (code, X86_CC_EQ, 0, TRUE);
+ }
+ x86_breakpoint (code); /* unhandled case */
+
+ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
+ mono_amd64_patch (br [i], code);
+ switch (i) {
+ case GSHAREDVT_RET_NONE:
+ break;
+ case GSHAREDVT_RET_IREGS_1:
+ amd64_mov_membase_reg (code, AMD64_R11, 0, return_regs [i - GSHAREDVT_RET_IREGS_1], 8);
+ break;
+ case GSHAREDVT_RET_R8:
+ amd64_sse_movsd_membase_reg (code, AMD64_R11, 0, AMD64_XMM0);
+ break;
+ default:
+ x86_breakpoint (code); /* can't handle specific case */
+ }
+
+ br_ret [b_ret_index ++] = code;
+ x86_jump32 (code, 0);
+ }
+
+ /* exit path */
+ for (i = 0; i < b_ret_index; ++i)
+ mono_amd64_patch (br_ret [i], code);
+
+ /* Exit code path */
+ amd64_leave (code);
+ amd64_ret (code);
+
+ g_assert ((code - buf) < buf_len);
+
+ if (info)
+ *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
+
+ mono_arch_flush_icache (buf, code - buf);
+ return buf;
+}
+
+#else
+
+gpointer
+mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif
+
+#else
+
+gpointer
+mono_amd64_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ *info = NULL;
+ return NULL;
+}
+
+#endif
\ No newline at end of file
* (C) 2001 Ximian, Inc.
* Copyright 2003-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
return buf;
}
-
-#if defined(ENABLE_GSHAREDVT) && defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
-
-#include "../../../mono-extensions/mono/mini/tramp-amd64-gsharedvt.c"
-
-#else
-
-gpointer
-mono_amd64_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
-{
- g_assert_not_reached ();
- return NULL;
-}
-
-gpointer
-mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
-{
- g_assert_not_reached ();
- return NULL;
-}
-
-gpointer
-mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
-{
- *info = NULL;
- return NULL;
-}
-
-#endif /* !ENABLE_GSHAREDVT */
--- /dev/null
+/*
+ * tramp-arm-gsharedvt.c: gsharedvt support code for arm
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ *
+ * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/abi-details.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
+#include <mono/metadata/tabledefs.h>
+#include <mono/metadata/profiler-private.h>
+#include <mono/arch/arm/arm-codegen.h>
+#include <mono/arch/arm/arm-vfp-codegen.h>
+
+#include "mini.h"
+#include "mini-arm.h"
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+
+static inline guint8*
+emit_bx (guint8* code, int reg)
+{
+ if (mono_arm_thumb_supported ())
+ ARM_BX (code, reg);
+ else
+ ARM_MOV_REG_REG (code, ARMREG_PC, reg);
+ return code;
+}
+
+
+gpointer
+mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
+{
+ int i;
+
+ /*
+ * The caller/callee regs are mapped to slot 0..3, stack slot 0 is mapped to slot 4, etc.
+ */
+
+ /* Set vtype ret arg */
+ if (info->vret_slot != -1) {
+ callee [info->vret_arg_reg] = &callee [info->vret_slot];
+ }
+
+ for (i = 0; i < info->map_count; ++i) {
+ int src = info->map [i * 2];
+ int dst = info->map [(i * 2) + 1];
+ int arg_marshal = (src >> 16) & 0xff;
+
+ switch (arg_marshal) {
+ case GSHAREDVT_ARG_NONE:
+ callee [dst] = caller [src];
+ break;
+ case GSHAREDVT_ARG_BYVAL_TO_BYREF:
+ /* gsharedvt argument passed by addr in reg/stack slot */
+ src = src & 0xffff;
+ callee [dst] = caller + src;
+ break;
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL: {
+ /* gsharedvt argument passed by value */
+ int nslots = (src >> 4) & 0xff;
+ int src_slot = src & 0xf;
+ int j;
+ gpointer *addr = caller [src_slot];
+
+ for (j = 0; j < nslots; ++j)
+ callee [dst + j] = addr [j];
+ break;
+ }
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL_I1: {
+ int src_slot = src & 0xf;
+ gpointer *addr = caller [src_slot];
+
+ callee [dst] = GINT_TO_POINTER ((int)*(gint8*)addr);
+ break;
+ }
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL_I2: {
+ int src_slot = src & 0xf;
+ gpointer *addr = caller [src_slot];
+
+ callee [dst] = GINT_TO_POINTER ((int)*(gint16*)addr);
+ break;
+ }
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL_U1: {
+ int src_slot = src & 0xf;
+ gpointer *addr = caller [src_slot];
+
+ callee [dst] = GUINT_TO_POINTER ((guint)*(guint8*)addr);
+ break;
+ }
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL_U2: {
+ int src_slot = src & 0xf;
+ gpointer *addr = caller [src_slot];
+
+ callee [dst] = GUINT_TO_POINTER ((guint)*(guint16*)addr);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ if (info->vcall_offset != -1) {
+ MonoObject *this_obj = caller [0];
+
+ if (G_UNLIKELY (!this_obj))
+ return NULL;
+ if (info->vcall_offset == MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET)
+ /* delegate invoke */
+ return ((MonoDelegate*)this_obj)->invoke_impl;
+ else
+ return *(gpointer*)((char*)this_obj->vtable + info->vcall_offset);
+ } else if (info->calli) {
+ /* The address to call is passed in the mrgctx reg */
+ return mrgctx_reg;
+ } else {
+ return info->addr;
+ }
+}
+
+#ifndef DISABLE_JIT
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *code, *buf;
+ int buf_len, cfa_offset;
+ GSList *unwind_ops = NULL;
+ MonoJumpInfo *ji = NULL;
+ guint8 *br_out, *br [16], *br_ret [16];
+ int i, arg_reg, npushed, info_offset, mrgctx_offset, caller_reg_area_offset, callee_reg_area_offset;
+ int lr_offset, fp, br_ret_index, args_size;
+
+ buf_len = 512;
+ buf = code = mono_global_codeman_reserve (buf_len);
+
+ arg_reg = ARMREG_R0;
+ /* Registers pushed by the arg trampoline */
+ npushed = 4;
+
+ // ios abi compatible frame
+ fp = ARMREG_R7;
+ cfa_offset = npushed * sizeof (gpointer);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, cfa_offset);
+ ARM_PUSH (code, (1 << fp) | (1 << ARMREG_LR));
+ cfa_offset += 2 * sizeof (gpointer);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, fp, (- cfa_offset));
+ mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_LR, ((- cfa_offset) + 4));
+ ARM_MOV_REG_REG (code, fp, ARMREG_SP);
+ mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, fp);
+ /* Allocate stack frame */
+ ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 32);
+ info_offset = -4;
+ mrgctx_offset = -8;
+ callee_reg_area_offset = - (6 * 4);
+ caller_reg_area_offset = cfa_offset - (npushed * sizeof (gpointer));
+ lr_offset = 4;
+ /* Save info struct which is in r0 */
+ ARM_STR_IMM (code, arg_reg, fp, info_offset);
+ /* Save rgctx reg */
+ ARM_STR_IMM (code, MONO_ARCH_RGCTX_REG, fp, mrgctx_offset);
+ /* Allocate callee area */
+ ARM_LDR_IMM (code, ARMREG_IP, arg_reg, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage));
+ ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
+ /* Allocate callee register area just below the callee area so it can be accessed from start_gsharedvt_call using negative offsets */
+ ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 4 * sizeof (gpointer));
+
+ /*
+ * The stack now looks like this:
+ * <caller frame>
+ * <saved r0-r3, lr>
+ * <saved fp> <- fp
+ * <our frame>
+ * <callee area> <- sp
+ */
+ g_assert (mono_arm_thumb_supported ());
+
+ /* Call start_gsharedvt_call () */
+ /* 4 arguments, needs 0 stack slot, need to clean it up after the call */
+ args_size = 0 * sizeof (gpointer);
+ ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, args_size);
+ /* arg1 == info */
+ ARM_LDR_IMM (code, ARMREG_R0, fp, info_offset);
+ /* arg2 == caller stack area */
+ ARM_ADD_REG_IMM8 (code, ARMREG_R1, fp, cfa_offset - 4 * sizeof (gpointer));
+ /* arg3 == callee stack area */
+ ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, args_size);
+ /* arg4 == mrgctx reg */
+ ARM_LDR_IMM (code, ARMREG_R3, fp, mrgctx_offset);
+ /* Make the call */
+ if (aot) {
+ ji = mono_patch_info_list_prepend (ji, code - buf, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_arm_start_gsharedvt_call");
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
+ ARM_B (code, 0);
+ *(gpointer*)code = NULL;
+ code += 4;
+ ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP);
+ } else {
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
+ ARM_B (code, 0);
+ *(gpointer*)code = mono_arm_start_gsharedvt_call;
+ code += 4;
+ }
+ ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
+ code = emit_bx (code, ARMREG_IP);
+ /* Clean up stack */
+ ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, args_size);
+
+ /* Make the real method call */
+ /* R0 contains the addr to call */
+ ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_R0);
+ /* Load argument registers */
+ ARM_LDM (code, ARMREG_SP, (1 << ARMREG_R0) | (1 << ARMREG_R1) | (1 << ARMREG_R2) | (1 << ARMREG_R3));
+ /* Pop callee register area */
+ ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 4 * sizeof (gpointer));
+ /* Load rgctx */
+ ARM_LDR_IMM (code, MONO_ARCH_RGCTX_REG, fp, mrgctx_offset);
+ /* Make the call */
+#if 0
+ ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, addr));
+#endif
+ /* mono_arch_find_imt_method () depends on this */
+ ARM_ADD_REG_IMM8 (code, ARMREG_LR, ARMREG_PC, 4);
+ ARM_BX (code, ARMREG_IP);
+ *((gpointer*)code) = NULL;
+ code += 4;
+
+ br_ret_index = 0;
+
+ /* Branch between IN/OUT cases */
+ ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in));
+
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, 1);
+ br_out = code;
+ ARM_B_COND (code, ARMCOND_NE, 0);
+
+ /* IN CASE */
+
+ /* LR == return marshalling type */
+ ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal));
+
+ /* Continue if no marshalling required */
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_NONE);
+ br_ret [br_ret_index ++] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+
+ /* Compute vret area address in LR */
+ ARM_LDR_IMM (code, ARMREG_LR, fp, info_offset);
+ ARM_LDR_IMM (code, ARMREG_LR, ARMREG_LR, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot));
+ /* The slot value is off by 4 */
+ ARM_SUB_REG_IMM8 (code, ARMREG_LR, ARMREG_LR, 4);
+ ARM_SHL_IMM (code, ARMREG_LR, ARMREG_LR, 2);
+ ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ARMREG_SP);
+
+ /* Branch to specific marshalling code */
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_IREG);
+ br [0] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_IREGS);
+ br [1] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_I1);
+ br [2] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_U1);
+ br [3] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_I2);
+ br [4] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_U2);
+ br [5] = code;
+ ARM_B_COND (code, ARMCOND_EQ, 0);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+
+ /* IN IREG case */
+ arm_patch (br [0], code);
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, 0);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+ /* IN IREGS case */
+ arm_patch (br [1], code);
+ ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, 0);
+ ARM_LDR_IMM (code, ARMREG_R1, ARMREG_LR, 4);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+ /* I1 case */
+ arm_patch (br [2], code);
+ ARM_LDRSB_IMM (code, ARMREG_R0, ARMREG_LR, 0);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+ /* U1 case */
+ arm_patch (br [3], code);
+ ARM_LDRB_IMM (code, ARMREG_R0, ARMREG_LR, 0);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+ /* I2 case */
+ arm_patch (br [4], code);
+ ARM_LDRSH_IMM (code, ARMREG_R0, ARMREG_LR, 0);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+ /* U2 case */
+ arm_patch (br [5], code);
+ ARM_LDRH_IMM (code, ARMREG_R0, ARMREG_LR, 0);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+
+ /* OUT CASE */
+ arm_patch (br_out, code);
+
+ /* Marshal return value */
+ ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal));
+
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_IREGS);
+ br [0] = code;
+ ARM_B_COND (code, ARMCOND_NE, 0);
+
+ /* OUT IREGS case */
+ /* Load vtype ret addr from the caller arg regs */
+ ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_reg));
+ ARM_SHL_IMM (code, ARMREG_IP, ARMREG_IP, 2);
+ ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, fp);
+ ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, caller_reg_area_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 0);
+ /* Save both registers for simplicity */
+ ARM_STR_IMM (code, ARMREG_R0, ARMREG_IP, 0);
+ ARM_STR_IMM (code, ARMREG_R1, ARMREG_IP, 4);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+ arm_patch (br [0], code);
+
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_IREG);
+ br [0] = code;
+ ARM_B_COND (code, ARMCOND_NE, 0);
+
+ /* OUT IREG case */
+ /* Load vtype ret addr from the caller arg regs */
+ ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_reg));
+ ARM_SHL_IMM (code, ARMREG_IP, ARMREG_IP, 2);
+ ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, fp);
+ ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, caller_reg_area_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 0);
+ /* Save the return value to the buffer pointed to by the vret addr */
+ ARM_STR_IMM (code, ARMREG_R0, ARMREG_IP, 0);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+ arm_patch (br [0], code);
+
+ ARM_CMP_REG_IMM8 (code, ARMREG_IP, GSHAREDVT_RET_U1);
+ br [0] = code;
+ ARM_B_COND (code, ARMCOND_NE, 0);
+
+ /* OUT U1 case */
+ /* Load vtype ret addr from the caller arg regs */
+ ARM_LDR_IMM (code, ARMREG_IP, fp, info_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_reg));
+ ARM_SHL_IMM (code, ARMREG_IP, ARMREG_IP, 2);
+ ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, fp);
+ ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, caller_reg_area_offset);
+ ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 0);
+ /* Save the return value to the buffer pointed to by the vret addr */
+ ARM_STRB_IMM (code, ARMREG_R0, ARMREG_IP, 0);
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+ arm_patch (br [0], code);
+
+ /* OUT other cases */
+ br_ret [br_ret_index ++] = code;
+ ARM_B (code, 0);
+
+ for (i = 0; i < br_ret_index; ++i)
+ arm_patch (br_ret [i], code);
+
+ /* Normal return */
+ /* Restore registers + stack */
+ ARM_MOV_REG_REG (code, ARMREG_SP, fp);
+ ARM_LDM (code, fp, (1 << fp) | (1 << ARMREG_LR));
+ ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, cfa_offset);
+ /* Return */
+ ARM_BX (code, ARMREG_LR);
+
+ g_assert ((code - buf) < buf_len);
+
+ if (info)
+ *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
+
+ mono_arch_flush_icache (buf, code - buf);
+ return buf;
+}
+
+#else
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif
+
+
+#else
+
+
+gpointer
+mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ *info = NULL;
+ return NULL;
+}
+
+
+#endif
* (C) 2001-2003 Ximian, Inc.
* Copyright 2003-2011 Novell Inc
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
ARM_STR_IMM (code, ARMREG_R0, ARMREG_FP, MONO_STRUCT_OFFSET (MonoContext, regs) + 4 * ARMREG_SP);
/* make ctx.eip hold the address of the call. */
- ARM_SUB_REG_IMM8 (code, ARMREG_LR, ARMREG_LR, 4);
+ //ARM_SUB_REG_IMM8 (code, ARMREG_LR, ARMREG_LR, 4);
ARM_STR_IMM (code, ARMREG_LR, ARMREG_FP, MONO_STRUCT_OFFSET (MonoContext, pc));
/* r0 now points to the MonoContext */
}
#endif
-
-#if defined(ENABLE_GSHAREDVT)
-
-#include "../../../mono-extensions/mono/mini/tramp-arm-gsharedvt.c"
-
-#else
-
-gpointer
-mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
-{
- g_assert_not_reached ();
- return NULL;
-}
-
-gpointer
-mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
-{
- *info = NULL;
- return NULL;
-}
-
-#endif /* !MONOTOUCH */
--- /dev/null
+/*
+ * tramp-arm64-gsharedvt.c: gsharedvt support code for arm64
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ *
+ * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include <mono/metadata/abi-details.h>
+
+#include "mini.h"
+#include "mini-arm64.h"
+#include "mini-arm64-gsharedvt.h"
+
+/*
+ * GSHAREDVT
+ */
+#ifdef MONO_ARCH_GSHARED_SUPPORTED
+
+/*
+ * mono_arch_get_gsharedvt_arg_trampoline:
+ *
+ * See tramp-x86.c for documentation.
+ */
+gpointer
+mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
+{
+ guint8 *code, *buf;
+ int buf_len = 40;
+
+ /*
+ * Return a trampoline which calls ADDR passing in ARG.
+ * Pass the argument in ip1, clobbering ip0.
+ */
+ buf = code = mono_global_codeman_reserve (buf_len);
+
+ code = mono_arm_emit_imm64 (code, ARMREG_IP1, (guint64)arg);
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr);
+
+ arm_brx (code, ARMREG_IP0);
+
+ g_assert ((code - buf) < buf_len);
+ mono_arch_flush_icache (buf, code - buf);
+
+ return buf;
+}
+
+gpointer
+mono_arm_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
+{
+ int i;
+
+ /* Set vtype ret arg */
+ if (info->vret_slot != -1) {
+ g_assert (info->vret_slot);
+ callee [info->vret_arg_reg] = &callee [info->vret_slot];
+ }
+
+ for (i = 0; i < info->map_count; ++i) {
+ int src = info->map [i * 2];
+ int dst = info->map [(i * 2) + 1];
+ int arg_marshal = (src >> 18) & 0xf;
+ int arg_size = (src >> 22) & 0xf;
+
+ if (G_UNLIKELY (arg_size)) {
+ int src_offset = (src >> 26) & 0xf;
+ int dst_offset = (dst >> 26) & 0xf;
+ int src_slot, dst_slot;
+ guint8 *src_ptr, *dst_ptr;
+
+ /*
+ * Argument passed in part of a stack slot on ios.
+ * src_offset/dst_offset is the offset within the stack slot.
+ */
+ switch (arg_marshal) {
+ case GSHAREDVT_ARG_NONE:
+ src_slot = src & 0xffff;
+ dst_slot = dst & 0xffff;
+ src_ptr = (guint8*)(caller + src_slot) + src_offset;
+ dst_ptr = (guint8*)(callee + dst_slot) + dst_offset;
+ break;
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL:
+ src_slot = src & 0x3f;
+ dst_slot = dst & 0xffff;
+ src_ptr = caller [src_slot];
+ dst_ptr = (guint8*)(callee + dst_slot) + dst_offset;
+ break;
+ case GSHAREDVT_ARG_BYVAL_TO_BYREF_HFAR4:
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL_HFAR4:
+ case GSHAREDVT_ARG_BYREF_TO_BYREF:
+ g_assert_not_reached ();
+ break;
+ case GSHAREDVT_ARG_BYVAL_TO_BYREF:
+ src_slot = src & 0x3f;
+ src_ptr = caller + src_slot + src_offset;
+ callee [dst] = src_ptr;
+ break;
+ default:
+ NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (arg_marshal == GSHAREDVT_ARG_BYVAL_TO_BYREF)
+ continue;
+
+ switch (arg_size) {
+ case GSHAREDVT_ARG_SIZE_I1:
+ *(gint8*)dst_ptr = *(gint8*)src_ptr;
+ break;
+ case GSHAREDVT_ARG_SIZE_U1:
+ *(guint8*)dst_ptr = *(guint8*)src_ptr;
+ break;
+ case GSHAREDVT_ARG_SIZE_I2:
+ *(gint16*)dst_ptr = *(gint16*)src_ptr;
+ break;
+ case GSHAREDVT_ARG_SIZE_U2:
+ *(guint16*)dst_ptr = *(guint16*)src_ptr;
+ break;
+ case GSHAREDVT_ARG_SIZE_I4:
+ *(gint32*)dst_ptr = *(gint32*)src_ptr;
+ break;
+ case GSHAREDVT_ARG_SIZE_U4:
+ *(guint32*)dst_ptr = *(guint32*)src_ptr;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ continue;
+ }
+
+ switch (arg_marshal) {
+ case GSHAREDVT_ARG_NONE:
+ callee [dst] = caller [src];
+ break;
+ case GSHAREDVT_ARG_BYVAL_TO_BYREF:
+ /* gsharedvt argument passed by addr in reg/stack slot */
+ src = src & 0x3f;
+ callee [dst] = caller + src;
+ break;
+ case GSHAREDVT_ARG_BYVAL_TO_BYREF_HFAR4: {
+ int nslots = (src >> 6) & 0xff;
+ int src_slot = src & 0x3f;
+ int j;
+ float *dst_arr = (float*)(caller + src_slot);
+
+ /* The r4 hfa is in separate slots, need to compress them together in place */
+ for (j = 0; j < nslots; ++j)
+ dst_arr [j] = *(float*)(caller + src_slot + j);
+
+ callee [dst] = caller + src_slot;
+ break;
+ }
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL: {
+ int nslots = (src >> 6) & 0xff;
+ int src_slot = src & 0x3f;
+ int j;
+ gpointer *addr = caller [src_slot];
+
+ for (j = 0; j < nslots; ++j)
+ callee [dst + j] = addr [j];
+ break;
+ }
+ case GSHAREDVT_ARG_BYREF_TO_BYVAL_HFAR4: {
+ int nslots = (src >> 6) & 0xff;
+ int src_slot = src & 0x3f;
+ int j;
+ guint32 *addr = (guint32*)(caller [src_slot]);
+
+ /* addr points to an array of floats, need to load them to registers */
+ for (j = 0; j < nslots; ++j)
+ callee [dst + j] = GUINT_TO_POINTER (addr [j]);
+ break;
+ }
+ case GSHAREDVT_ARG_BYREF_TO_BYREF: {
+ int src_slot = src & 0x3f;
+
+ callee [dst] = caller [src_slot];
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ if (info->vcall_offset != -1) {
+ MonoObject *this_obj = caller [0];
+
+ if (G_UNLIKELY (!this_obj))
+ return NULL;
+ if (info->vcall_offset == MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET)
+ /* delegate invoke */
+ return ((MonoDelegate*)this_obj)->invoke_impl;
+ else
+ return *(gpointer*)((char*)this_obj->vtable + info->vcall_offset);
+ } else if (info->calli) {
+ /* The address to call is passed in the mrgctx reg */
+ return mrgctx_reg;
+ } else {
+ return info->addr;
+ }
+}
+
+#ifndef DISABLE_JIT
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *code, *buf;
+ int buf_len, cfa_offset;
+ GSList *unwind_ops = NULL;
+ MonoJumpInfo *ji = NULL;
+ guint8 *br_out, *br [64], *br_ret [64], *bcc_ret [64];
+ int i, n_arg_regs, n_arg_fregs, offset, arg_reg, info_offset, rgctx_arg_reg_offset;
+ int caller_reg_area_offset, callee_reg_area_offset, callee_stack_area_offset;
+ int br_ret_index, bcc_ret_index;
+
+ buf_len = 2048;
+ buf = code = mono_global_codeman_reserve (buf_len);
+
+ /*
+ * We are being called by an gsharedvt arg trampoline, the info argument is in IP1.
+ */
+ arg_reg = ARMREG_IP1;
+ n_arg_regs = NUM_GSHAREDVT_ARG_GREGS;
+ n_arg_fregs = NUM_GSHAREDVT_ARG_FREGS;
+
+ /* Compute stack frame size and offsets */
+ offset = 0;
+ /* frame block */
+ offset += 2 * 8;
+ /* info argument */
+ info_offset = offset;
+ offset += 8;
+ /* saved rgctx */
+ rgctx_arg_reg_offset = offset;
+ offset += 8;
+ /* alignment */
+ offset += 8;
+ /* argument regs */
+ caller_reg_area_offset = offset;
+ offset += (n_arg_regs + n_arg_fregs) * 8;
+
+ /* We need the argument regs to be saved at the top of the frame */
+ g_assert (offset % MONO_ARCH_FRAME_ALIGNMENT == 0);
+
+ cfa_offset = offset;
+
+ /* Setup frame */
+ arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -cfa_offset);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, cfa_offset);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_FP, -cfa_offset + 0);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_LR, -cfa_offset + 8);
+ arm_movspx (code, ARMREG_FP, ARMREG_SP);
+ mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, ARMREG_FP);
+
+ /* Save info argument */
+ arm_strx (code, arg_reg, ARMREG_FP, info_offset);
+
+ /* Save rgxctx */
+ arm_strx (code, MONO_ARCH_RGCTX_REG, ARMREG_FP, rgctx_arg_reg_offset);
+
+ /* Save argument regs below the stack arguments */
+ for (i = 0; i < n_arg_regs; ++i)
+ arm_strx (code, i, ARMREG_SP, caller_reg_area_offset + (i * 8));
+ // FIXME: Only do this if fp regs are used
+ for (i = 0; i < n_arg_fregs; ++i)
+ arm_strfpx (code, i, ARMREG_SP, caller_reg_area_offset + ((n_arg_regs + i) * 8));
+
+ /* Allocate callee area */
+ arm_ldrw (code, ARMREG_IP0, arg_reg, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage));
+ arm_movspx (code, ARMREG_LR, ARMREG_SP);
+ arm_subx (code, ARMREG_LR, ARMREG_LR, ARMREG_IP0);
+ arm_movspx (code, ARMREG_SP, ARMREG_LR);
+ /* Allocate callee register area just below the callee area so it can be accessed from start_gsharedvt_call using negative offsets */
+ /* The + 8 is for alignment */
+ callee_reg_area_offset = 8;
+ callee_stack_area_offset = callee_reg_area_offset + (n_arg_regs * sizeof (gpointer));
+ arm_subx_imm (code, ARMREG_SP, ARMREG_SP, ((n_arg_regs + n_arg_fregs) * sizeof (gpointer)) + 8);
+
+ /*
+ * The stack now looks like this:
+ * <caller frame>
+ * <saved r0-r8>
+ * <our frame>
+ * <saved fp, lr> <- fp
+ * <callee area> <- sp
+ */
+
+ /* Call start_gsharedvt_call () */
+ /* arg1 == info */
+ arm_ldrx (code, ARMREG_R0, ARMREG_FP, info_offset);
+ /* arg2 = caller stack area */
+ arm_addx_imm (code, ARMREG_R1, ARMREG_FP, caller_reg_area_offset);
+ /* arg3 == callee stack area */
+ arm_addx_imm (code, ARMREG_R2, ARMREG_SP, callee_reg_area_offset);
+ /* arg4 = mrgctx reg */
+ arm_ldrx (code, ARMREG_R3, ARMREG_FP, rgctx_arg_reg_offset);
+
+ if (aot)
+ code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_arm_start_gsharedvt_call");
+ else
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)mono_arm_start_gsharedvt_call);
+ arm_blrx (code, ARMREG_IP0);
+
+ /* Make the real method call */
+ /* R0 contains the addr to call */
+ arm_movx (code, ARMREG_IP1, ARMREG_R0);
+ /* Load rgxctx */
+ arm_ldrx (code, MONO_ARCH_RGCTX_REG, ARMREG_FP, rgctx_arg_reg_offset);
+ /* Load argument registers */
+ // FIXME:
+ for (i = 0; i < n_arg_regs; ++i)
+ arm_ldrx (code, i, ARMREG_SP, callee_reg_area_offset + (i * 8));
+ // FIXME: Only do this if needed
+ for (i = 0; i < n_arg_fregs; ++i)
+ arm_ldrfpx (code, i, ARMREG_SP, callee_reg_area_offset + ((n_arg_regs + i) * 8));
+ /* Clear callee reg area */
+ arm_addx_imm (code, ARMREG_SP, ARMREG_SP, ((n_arg_regs + n_arg_fregs) * sizeof (gpointer)) + 8);
+ /* Make the call */
+ arm_blrx (code, ARMREG_IP1);
+
+ br_ret_index = 0;
+ bcc_ret_index = 0;
+
+ // FIXME: Use a switch
+ /* Branch between IN/OUT cases */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
+ arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in));
+ br_out = code;
+ arm_cbzx (code, ARMREG_IP1, 0);
+
+ /* IN CASE */
+
+ /* IP1 == return marshalling type */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
+ arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal));
+
+ /* Continue if no marshalling required */
+ // FIXME: Use cmpx_imm
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, GSHAREDVT_RET_NONE);
+ arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
+ bcc_ret [bcc_ret_index ++] = code;
+ arm_bcc (code, ARMCOND_EQ, 0);
+
+ /* Compute vret area address in LR */
+ arm_ldrx (code, ARMREG_LR, ARMREG_FP, info_offset);
+ arm_ldrw (code, ARMREG_LR, ARMREG_LR, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot));
+ arm_subx_imm (code, ARMREG_LR, ARMREG_LR, n_arg_regs + n_arg_fregs);
+ arm_lslx (code, ARMREG_LR, ARMREG_LR, 3);
+ arm_movspx (code, ARMREG_IP0, ARMREG_SP);
+ arm_addx (code, ARMREG_LR, ARMREG_IP0, ARMREG_LR);
+
+ /* Branch to specific marshalling code */
+ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, i);
+ arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
+ br [i] = code;
+ arm_bcc (code, ARMCOND_EQ, 0);
+ }
+
+ arm_brk (code, 0);
+
+ /*
+ * The address of the return value area is in LR, have to load it into
+ * registers.
+ */
+ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
+ mono_arm_patch (br [i], code, MONO_R_ARM64_BCC);
+ switch (i) {
+ case GSHAREDVT_RET_NONE:
+ break;
+ case GSHAREDVT_RET_I8:
+ arm_ldrx (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_I1:
+ arm_ldrsbx (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_U1:
+ arm_ldrb (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_I2:
+ arm_ldrshx (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_U2:
+ arm_ldrh (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_I4:
+ arm_ldrswx (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_U4:
+ arm_ldrw (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_R8:
+ arm_ldrfpx (code, ARMREG_D0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_R4:
+ arm_ldrfpw (code, ARMREG_D0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_IREGS_1:
+ case GSHAREDVT_RET_IREGS_2:
+ case GSHAREDVT_RET_IREGS_3:
+ case GSHAREDVT_RET_IREGS_4:
+ case GSHAREDVT_RET_IREGS_5:
+ case GSHAREDVT_RET_IREGS_6:
+ case GSHAREDVT_RET_IREGS_7:
+ case GSHAREDVT_RET_IREGS_8: {
+ int j;
+
+ for (j = 0; j < i - GSHAREDVT_RET_IREGS_1 + 1; ++j)
+ arm_ldrx (code, j, ARMREG_LR, j * 8);
+ break;
+ }
+ case GSHAREDVT_RET_HFAR8_1:
+ case GSHAREDVT_RET_HFAR8_2:
+ case GSHAREDVT_RET_HFAR8_3:
+ case GSHAREDVT_RET_HFAR8_4: {
+ int j;
+
+ for (j = 0; j < i - GSHAREDVT_RET_HFAR8_1 + 1; ++j)
+ arm_ldrfpx (code, j, ARMREG_LR, j * 8);
+ break;
+ }
+ case GSHAREDVT_RET_HFAR4_1:
+ case GSHAREDVT_RET_HFAR4_2:
+ case GSHAREDVT_RET_HFAR4_3:
+ case GSHAREDVT_RET_HFAR4_4: {
+ int j;
+
+ for (j = 0; j < i - GSHAREDVT_RET_HFAR4_1 + 1; ++j)
+ arm_ldrfpw (code, j, ARMREG_LR, j * 4);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ br_ret [br_ret_index ++] = code;
+ arm_b (code, 0);
+ }
+
+ /* OUT CASE */
+ mono_arm_patch (br_out, code, MONO_R_ARM64_CBZ);
+
+ /* Compute vret area address in LR */
+ arm_ldrx (code, ARMREG_LR, ARMREG_FP, caller_reg_area_offset + (ARMREG_R8 * 8));
+
+ /* IP1 == return marshalling type */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, info_offset);
+ arm_ldrw (code, ARMREG_IP1, ARMREG_IP1, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal));
+
+ /* Branch to specific marshalling code */
+ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, i);
+ arm_cmpx (code, ARMREG_IP0, ARMREG_IP1);
+ br [i] = code;
+ arm_bcc (code, ARMCOND_EQ, 0);
+ }
+
+ /*
+ * The return value is in registers, need to save to the return area passed by the caller in
+ * R8.
+ */
+ for (i = GSHAREDVT_RET_NONE; i < GSHAREDVT_RET_NUM; ++i) {
+ mono_arm_patch (br [i], code, MONO_R_ARM64_BCC);
+ switch (i) {
+ case GSHAREDVT_RET_NONE:
+ break;
+ case GSHAREDVT_RET_I8:
+ arm_strx (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_I1:
+ case GSHAREDVT_RET_U1:
+ arm_strb (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_I2:
+ case GSHAREDVT_RET_U2:
+ arm_strh (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_I4:
+ case GSHAREDVT_RET_U4:
+ arm_strw (code, ARMREG_R0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_R8:
+ arm_strfpx (code, ARMREG_D0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_R4:
+ arm_strfpw (code, ARMREG_D0, ARMREG_LR, 0);
+ break;
+ case GSHAREDVT_RET_IREGS_1:
+ case GSHAREDVT_RET_IREGS_2:
+ case GSHAREDVT_RET_IREGS_3:
+ case GSHAREDVT_RET_IREGS_4:
+ case GSHAREDVT_RET_IREGS_5:
+ case GSHAREDVT_RET_IREGS_6:
+ case GSHAREDVT_RET_IREGS_7:
+ case GSHAREDVT_RET_IREGS_8: {
+ int j;
+
+ for (j = 0; j < i - GSHAREDVT_RET_IREGS_1 + 1; ++j)
+ arm_strx (code, j, ARMREG_LR, j * 8);
+ break;
+ }
+ case GSHAREDVT_RET_HFAR8_1:
+ case GSHAREDVT_RET_HFAR8_2:
+ case GSHAREDVT_RET_HFAR8_3:
+ case GSHAREDVT_RET_HFAR8_4: {
+ int j;
+
+ for (j = 0; j < i - GSHAREDVT_RET_HFAR8_1 + 1; ++j)
+ arm_strfpx (code, j, ARMREG_LR, j * 8);
+ break;
+ }
+ case GSHAREDVT_RET_HFAR4_1:
+ case GSHAREDVT_RET_HFAR4_2:
+ case GSHAREDVT_RET_HFAR4_3:
+ case GSHAREDVT_RET_HFAR4_4: {
+ int j;
+
+ for (j = 0; j < i - GSHAREDVT_RET_HFAR4_1 + 1; ++j)
+ arm_strfpw (code, j, ARMREG_LR, j * 4);
+ break;
+ }
+ default:
+ arm_brk (code, i);
+ break;
+ }
+ br_ret [br_ret_index ++] = code;
+ arm_b (code, 0);
+ }
+
+ arm_brk (code, 0);
+
+ for (i = 0; i < br_ret_index; ++i)
+ mono_arm_patch (br_ret [i], code, MONO_R_ARM64_B);
+ for (i = 0; i < bcc_ret_index; ++i)
+ mono_arm_patch (bcc_ret [i], code, MONO_R_ARM64_BCC);
+
+ /* Normal return */
+ arm_movspx (code, ARMREG_SP, ARMREG_FP);
+ arm_ldpx_post (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, offset);
+ arm_retx (code, ARMREG_LR);
+
+ g_assert ((code - buf) < buf_len);
+
+ if (info)
+ *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
+
+ mono_arch_flush_icache (buf, code - buf);
+ return buf;
+}
+
+#else
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif
+
+#else
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ if (info)
+ *info = NULL;
+ return NULL;
+}
+
+gpointer
+mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif /* MONO_ARCH_GSHARED_SUPPORTED */
\ No newline at end of file
-#include "../../../mono-extensions/mono/mini/tramp-arm64.c"
+/*
+ * tramp-arm64.c: JIT trampoline code for ARM64
+ *
+ * Copyright 2013 Xamarin Inc
+ *
+ * Based on tramp-arm.c:
+ *
+ * Authors:
+ * Paolo Molaro (lupus@ximian.com)
+ *
+ * (C) 2001-2003 Ximian, Inc.
+ * Copyright 2003-2011 Novell Inc
+ * Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include "mini.h"
+#include "debugger-agent.h"
+
+#include <mono/arch/arm64/arm64-codegen.h>
+#include <mono/metadata/abi-details.h>
+
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+void
+mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr)
+{
+ mono_arm_patch (code_ptr - 4, addr, MONO_R_ARM64_BL);
+ mono_arch_flush_icache (code_ptr - 4, 4);
+}
+
+void
+mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
+{
+ guint32 ins;
+ guint64 slot_addr;
+ int disp;
+
+ /*
+ * Decode the address loaded by the PLT entry emitted by arch_emit_plt_entry () in
+ * aot-compiler.c
+ */
+
+ /* adrp */
+ ins = ((guint32*)code) [0];
+ g_assert (((ins >> 24) & 0x1f) == 0x10);
+ disp = (((ins >> 5) & 0x7ffff) << 2) | ((ins >> 29) & 0x3);
+ /* FIXME: disp is signed */
+ g_assert ((disp >> 20) == 0);
+
+ slot_addr = ((guint64)code + (disp << 12)) & ~0xfff;
+
+ /* add x16, x16, :lo12:got */
+ ins = ((guint32*)code) [1];
+ g_assert (((ins >> 22) & 0x3) == 0);
+ slot_addr += (ins >> 10) & 0xfff;
+
+ /* ldr x16, [x16, <offset>] */
+ ins = ((guint32*)code) [2];
+ g_assert (((ins >> 24) & 0x3f) == 0x39);
+ slot_addr += ((ins >> 10) & 0xfff) * 8;
+
+ g_assert (*(guint64*)slot_addr);
+ *(gpointer*)slot_addr = addr;
+}
+
+guint8*
+mono_arch_get_call_target (guint8 *code)
+{
+ guint32 imm;
+ int disp;
+
+ code -= 4;
+
+ imm = *(guint32*)code;
+ /* Should be a bl */
+ g_assert (((imm >> 31) & 0x1) == 0x1);
+ g_assert (((imm >> 26) & 0x7) == 0x5);
+
+ disp = (imm & 0x3ffffff);
+ if ((disp >> 25) != 0)
+ /* Negative, sing extend to 32 bits */
+ disp = disp | 0xfc000000;
+
+ return code + (disp * 4);
+}
+
+guint32
+mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code)
+{
+ /* The offset is stored as the 5th word of the plt entry */
+ return ((guint32*)plt_entry) [4];
+}
+
+#ifndef DISABLE_JIT
+
+guchar*
+mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *code, *buf, *tramp;
+ int i, buf_len, imm;
+ int frame_size, offset, gregs_offset, num_fregs, fregs_offset, arg_offset, lmf_offset;
+ guint64 gregs_regset;
+ GSList *unwind_ops = NULL;
+ MonoJumpInfo *ji = NULL;
+ char *tramp_name;
+
+ buf_len = 768;
+ buf = code = mono_global_codeman_reserve (buf_len);
+
+ /*
+ * We are getting called by a specific trampoline, ip1 contains the trampoline argument.
+ */
+
+ /* Compute stack frame size and offsets */
+ offset = 0;
+ /* frame block */
+ offset += 2 * 8;
+ /* gregs */
+ gregs_offset = offset;
+ offset += 32 * 8;
+ /* fregs */
+ // FIXME: Save 128 bits
+ /* Only have to save the argument regs */
+ num_fregs = 8;
+ fregs_offset = offset;
+ offset += num_fregs * 8;
+ /* arg */
+ arg_offset = offset;
+ offset += 8;
+ /* LMF */
+ lmf_offset = offset;
+ offset += sizeof (MonoLMF);
+ //offset += 22 * 8;
+ frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+
+ /* Setup stack frame */
+ imm = frame_size;
+ while (imm > 256) {
+ arm_subx_imm (code, ARMREG_SP, ARMREG_SP, 256);
+ imm -= 256;
+ }
+ arm_subx_imm (code, ARMREG_SP, ARMREG_SP, imm);
+ arm_stpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0);
+ arm_movspx (code, ARMREG_FP, ARMREG_SP);
+
+ /* Save gregs */
+ // FIXME: Optimize this
+ gregs_regset = ~((1 << ARMREG_FP) | (1 << ARMREG_SP));
+ code = mono_arm_emit_store_regarray (code, gregs_regset, ARMREG_FP, gregs_offset);
+ /* Save fregs */
+ for (i = 0; i < num_fregs; ++i)
+ arm_strfpx (code, i, ARMREG_FP, fregs_offset + (i * 8));
+ /* Save trampoline arg */
+ arm_strx (code, ARMREG_IP1, ARMREG_FP, arg_offset);
+
+ /* Setup LMF */
+ arm_addx_imm (code, ARMREG_IP0, ARMREG_FP, lmf_offset);
+ code = mono_arm_emit_store_regset (code, MONO_ARCH_LMF_REGS, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoLMF, gregs));
+ /* Save caller fp */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, 0);
+ arm_strx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoLMF, gregs) + (MONO_ARCH_LMF_REG_FP * 8));
+ /* Save caller sp */
+ arm_movx (code, ARMREG_IP1, ARMREG_FP);
+ imm = frame_size;
+ while (imm > 256) {
+ arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 256);
+ imm -= 256;
+ }
+ arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, imm);
+ arm_strx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoLMF, gregs) + (MONO_ARCH_LMF_REG_SP * 8));
+ /* Save caller pc */
+ if (tramp_type == MONO_TRAMPOLINE_JUMP)
+ arm_movx (code, ARMREG_LR, ARMREG_RZR);
+ else
+ arm_ldrx (code, ARMREG_LR, ARMREG_FP, 8);
+ arm_strx (code, ARMREG_LR, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoLMF, pc));
+
+ /* Save LMF */
+ /* Similar to emit_save_lmf () */
+ if (aot) {
+ code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_get_lmf_addr");
+ } else {
+ tramp = (guint8*)mono_get_lmf_addr;
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)tramp);
+ }
+ arm_blrx (code, ARMREG_IP0);
+ /* r0 contains the address of the tls slot holding the current lmf */
+ /* ip0 = lmf */
+ arm_addx_imm (code, ARMREG_IP0, ARMREG_FP, lmf_offset);
+ /* lmf->lmf_addr = lmf_addr */
+ arm_strx (code, ARMREG_R0, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoLMF, lmf_addr));
+ /* lmf->previous_lmf = *lmf_addr */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_R0, 0);
+ arm_strx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ /* *lmf_addr = lmf */
+ arm_strx (code, ARMREG_IP0, ARMREG_R0, 0);
+
+ /* Call the C trampoline function */
+ /* Arg 1 = gregs */
+ arm_addx_imm (code, ARMREG_R0, ARMREG_FP, gregs_offset);
+ /* Arg 2 = caller */
+ if (tramp_type == MONO_TRAMPOLINE_JUMP)
+ arm_movx (code, ARMREG_R1, ARMREG_RZR);
+ else
+ arm_ldrx (code, ARMREG_R1, ARMREG_FP, gregs_offset + (ARMREG_LR * 8));
+ /* Arg 3 = arg */
+ if (MONO_TRAMPOLINE_TYPE_HAS_ARG (tramp_type))
+ /* Passed in r0 */
+ arm_ldrx (code, ARMREG_R2, ARMREG_FP, gregs_offset + (ARMREG_R0 * 8));
+ else
+ arm_ldrx (code, ARMREG_R2, ARMREG_FP, arg_offset);
+ /* Arg 4 = trampoline addr */
+ arm_movx (code, ARMREG_R3, ARMREG_RZR);
+
+ if (aot) {
+ char *icall_name = g_strdup_printf ("trampoline_func_%d", tramp_type);
+ code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
+ } else {
+ tramp = (guint8*)mono_get_trampoline_func (tramp_type);
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)tramp);
+ }
+ arm_blrx (code, ARMREG_IP0);
+
+ /* Restore LMF */
+ /* Similar to emit_restore_lmf () */
+ /* Clobbers ip0/ip1 */
+ /* ip0 = lmf */
+ arm_addx_imm (code, ARMREG_IP0, ARMREG_FP, lmf_offset);
+ /* ip1 = lmf->previous_lmf */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
+ /* ip0 = lmf->lmf_addr */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoLMF, lmf_addr));
+ /* *lmf_addr = previous_lmf */
+ arm_strx (code, ARMREG_IP1, ARMREG_IP0, 0);
+
+ /* Save the result to ip1 */
+ arm_movx (code, ARMREG_IP1, ARMREG_R0);
+
+ /* Restore gregs */
+ /* Only have to load the argument regs (r0..r8) and the rgctx reg */
+ code = mono_arm_emit_load_regarray (code, 0x1ff | (1 << ARMREG_LR) | (1 << MONO_ARCH_RGCTX_REG), ARMREG_FP, gregs_offset);
+ /* Restore fregs */
+ for (i = 0; i < num_fregs; ++i)
+ arm_ldrfpx (code, i, ARMREG_FP, fregs_offset + (i * 8));
+
+ /* These trampolines return a value */
+ if (tramp_type == MONO_TRAMPOLINE_RGCTX_LAZY_FETCH)
+ arm_movx (code, ARMREG_R0, ARMREG_IP1);
+
+ /* Cleanup frame */
+ code = mono_arm_emit_destroy_frame (code, frame_size, ((1 << ARMREG_IP0)));
+
+ if (tramp_type == MONO_TRAMPOLINE_RGCTX_LAZY_FETCH)
+ arm_retx (code, ARMREG_LR);
+ else
+ arm_brx (code, ARMREG_IP1);
+
+ g_assert ((code - buf) < buf_len);
+ mono_arch_flush_icache (buf, code - buf);
+
+ if (info) {
+ tramp_name = mono_get_generic_trampoline_name (tramp_type);
+ *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
+ g_free (tramp_name);
+ }
+
+ return buf;
+}
+
+gpointer
+mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
+{
+ guint8 *code, *buf, *tramp;
+ int buf_len = 64;
+
+ /*
+ * Return a trampoline which calls generic trampoline TRAMP_TYPE passing in ARG1.
+ * Pass the argument in ip1, clobbering ip0.
+ */
+ tramp = mono_get_trampoline_code (tramp_type);
+
+ buf = code = mono_global_codeman_reserve (buf_len);
+
+ code = mono_arm_emit_imm64 (code, ARMREG_IP1, (guint64)arg1);
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)tramp);
+
+ arm_brx (code, ARMREG_IP0);
+
+ g_assert ((code - buf) < buf_len);
+ mono_arch_flush_icache (buf, code - buf);
+ if (code_len)
+ *code_len = code - buf;
+
+ return buf;
+}
+
+gpointer
+mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
+{
+ guint8 *code, *start;
+ guint32 size = 32;
+ MonoDomain *domain = mono_domain_get ();
+
+ start = code = mono_domain_code_reserve (domain, size);
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr);
+ arm_addx_imm (code, ARMREG_R0, ARMREG_R0, sizeof (MonoObject));
+ arm_brx (code, ARMREG_IP0);
+
+ g_assert ((code - start) <= size);
+ mono_arch_flush_icache (start, code - start);
+ return start;
+}
+
+gpointer
+mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
+{
+ guint8 *code, *start;
+ guint32 buf_len = 32;
+ MonoDomain *domain = mono_domain_get ();
+
+ start = code = mono_domain_code_reserve (domain, buf_len);
+ code = mono_arm_emit_imm64 (code, MONO_ARCH_RGCTX_REG, (guint64)mrgctx);
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr);
+ arm_brx (code, ARMREG_IP0);
+
+ g_assert ((code - start) <= buf_len);
+
+ mono_arch_flush_icache (start, code - start);
+
+ return start;
+}
+
+gpointer
+mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *code, *buf;
+ int buf_size;
+ int i, depth, index, njumps;
+ gboolean is_mrgctx;
+ guint8 **rgctx_null_jumps;
+ MonoJumpInfo *ji = NULL;
+ GSList *unwind_ops = NULL;
+ guint8 *tramp;
+ guint32 code_len;
+
+ is_mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
+ index = MONO_RGCTX_SLOT_INDEX (slot);
+ if (is_mrgctx)
+ index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
+ for (depth = 0; ; ++depth) {
+ int size = mono_class_rgctx_get_array_size (depth, is_mrgctx);
+
+ if (index < size - 1)
+ break;
+ index -= size - 1;
+ }
+
+ buf_size = 64 + 16 * depth;
+ code = buf = mono_global_codeman_reserve (buf_size);
+
+ rgctx_null_jumps = g_malloc0 (sizeof (guint8*) * (depth + 2));
+ njumps = 0;
+
+ /* The vtable/mrgtx is in R0 */
+ g_assert (MONO_ARCH_VTABLE_REG == ARMREG_R0);
+
+ if (is_mrgctx) {
+ /* get mrgctx ptr */
+ arm_movx (code, ARMREG_IP1, ARMREG_R0);
+ } else {
+ /* load rgctx ptr from vtable */
+ code = mono_arm_emit_ldrx (code, ARMREG_IP1, ARMREG_R0, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
+ /* is the rgctx ptr null? */
+ /* if yes, jump to actual trampoline */
+ rgctx_null_jumps [njumps ++] = code;
+ arm_cbzx (code, ARMREG_IP1, 0);
+ }
+
+ for (i = 0; i < depth; ++i) {
+ /* load ptr to next array */
+ if (is_mrgctx && i == 0) {
+ code = mono_arm_emit_ldrx (code, ARMREG_IP1, ARMREG_IP1, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
+ } else {
+ code = mono_arm_emit_ldrx (code, ARMREG_IP1, ARMREG_IP1, 0);
+ }
+ /* is the ptr null? */
+ /* if yes, jump to actual trampoline */
+ rgctx_null_jumps [njumps ++] = code;
+ arm_cbzx (code, ARMREG_IP1, 0);
+ }
+
+ /* fetch slot */
+ code = mono_arm_emit_ldrx (code, ARMREG_IP1, ARMREG_IP1, sizeof (gpointer) * (index + 1));
+ /* is the slot null? */
+ /* if yes, jump to actual trampoline */
+ rgctx_null_jumps [njumps ++] = code;
+ arm_cbzx (code, ARMREG_IP1, 0);
+ /* otherwise return, result is in IP1 */
+ arm_movx (code, ARMREG_R0, ARMREG_IP1);
+ arm_brx (code, ARMREG_LR);
+
+ g_assert (njumps <= depth + 2);
+ for (i = 0; i < njumps; ++i)
+ mono_arm_patch (rgctx_null_jumps [i], code, MONO_R_ARM64_CBZ);
+
+ g_free (rgctx_null_jumps);
+
+ /* Slowpath */
+
+ /* Call mono_rgctx_lazy_fetch_trampoline (), passing in the slot as argument */
+ /* The vtable/mrgctx is still in R0 */
+ if (aot) {
+ code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, g_strdup_printf ("specific_trampoline_lazy_fetch_%u", slot));
+ } else {
+ tramp = mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), &code_len);
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)tramp);
+ }
+ arm_brx (code, ARMREG_IP0);
+
+ mono_arch_flush_icache (buf, code - buf);
+
+ g_assert (code - buf <= buf_size);
+
+ if (info) {
+ char *name = mono_get_rgctx_fetch_trampoline_name (slot);
+ *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
+ g_free (name);
+ }
+
+ return buf;
+}
+
+gpointer
+mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *code, *buf;
+ int tramp_size;
+ MonoJumpInfo *ji = NULL;
+ GSList *unwind_ops = NULL;
+
+ g_assert (aot);
+
+ tramp_size = 32;
+
+ code = buf = mono_global_codeman_reserve (tramp_size);
+
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, 0);
+
+ // FIXME: Currently, we always go to the slow path.
+ /* Load trampoline addr */
+ arm_ldrx (code, ARMREG_IP0, MONO_ARCH_RGCTX_REG, 8);
+ /* The vtable/mrgctx is in R0 */
+ g_assert (MONO_ARCH_VTABLE_REG == ARMREG_R0);
+ arm_brx (code, ARMREG_IP0);
+
+ mono_arch_flush_icache (buf, code - buf);
+
+ g_assert (code - buf <= tramp_size);
+
+ if (info)
+ *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops);
+
+ return buf;
+}
+
+/*
+ * mono_arch_create_sdb_trampoline:
+ *
+ * Return a trampoline which captures the current context, passes it to
+ * debugger_agent_single_step_from_context ()/debugger_agent_breakpoint_from_context (),
+ * then restores the (potentially changed) context.
+ */
+guint8*
+mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot)
+{
+ int tramp_size = 512;
+ int offset, imm, frame_size, ctx_offset;
+ guint64 gregs_regset;
+ guint8 *code, *buf;
+ GSList *unwind_ops = NULL;
+ MonoJumpInfo *ji = NULL;
+
+ code = buf = mono_global_codeman_reserve (tramp_size);
+
+ /* Compute stack frame size and offsets */
+ offset = 0;
+ /* frame block */
+ offset += 2 * 8;
+ /* MonoContext */
+ ctx_offset = offset;
+ offset += sizeof (MonoContext);
+ offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+ frame_size = offset;
+
+ // FIXME: Unwind info
+
+ /* Setup stack frame */
+ imm = frame_size;
+ while (imm > 256) {
+ arm_subx_imm (code, ARMREG_SP, ARMREG_SP, 256);
+ imm -= 256;
+ }
+ arm_subx_imm (code, ARMREG_SP, ARMREG_SP, imm);
+ arm_stpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0);
+ arm_movspx (code, ARMREG_FP, ARMREG_SP);
+
+ /* Initialize a MonoContext structure on the stack */
+ /* No need to save fregs */
+ gregs_regset = ~((1 << ARMREG_FP) | (1 << ARMREG_SP));
+ code = mono_arm_emit_store_regarray (code, gregs_regset, ARMREG_FP, ctx_offset + G_STRUCT_OFFSET (MonoContext, regs));
+ /* Save caller fp */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, 0);
+ arm_strx (code, ARMREG_IP1, ARMREG_FP, ctx_offset + G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 8));
+ /* Save caller sp */
+ arm_movx (code, ARMREG_IP1, ARMREG_FP);
+ imm = frame_size;
+ while (imm > 256) {
+ arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 256);
+ imm -= 256;
+ }
+ arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, imm);
+ arm_strx (code, ARMREG_IP1, ARMREG_FP, ctx_offset + G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 8));
+ /* Save caller ip */
+ arm_ldrx (code, ARMREG_IP1, ARMREG_FP, 8);
+ arm_strx (code, ARMREG_IP1, ARMREG_FP, ctx_offset + G_STRUCT_OFFSET (MonoContext, pc));
+
+ /* Call the single step/breakpoint function in sdb */
+ /* Arg1 = ctx */
+ arm_addx_imm (code, ARMREG_R0, ARMREG_FP, ctx_offset);
+ if (aot) {
+ if (single_step)
+ code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, "debugger_agent_single_step_from_context");
+ else
+ code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, "debugger_agent_breakpoint_from_context");
+ } else {
+ gpointer addr = single_step ? debugger_agent_single_step_from_context : debugger_agent_breakpoint_from_context;
+
+ code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr);
+ }
+ arm_blrx (code, ARMREG_IP0);
+
+ /* Restore ctx */
+ /* Save fp/pc into the frame block */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, ctx_offset + G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 8));
+ arm_strx (code, ARMREG_IP0, ARMREG_FP, 0);
+ arm_ldrx (code, ARMREG_IP0, ARMREG_FP, ctx_offset + G_STRUCT_OFFSET (MonoContext, pc));
+ arm_strx (code, ARMREG_IP0, ARMREG_FP, 8);
+ gregs_regset = ~((1 << ARMREG_FP) | (1 << ARMREG_SP));
+ code = mono_arm_emit_load_regarray (code, gregs_regset, ARMREG_FP, ctx_offset + G_STRUCT_OFFSET (MonoContext, regs));
+
+ code = mono_arm_emit_destroy_frame (code, frame_size, ((1 << ARMREG_IP0) | (1 << ARMREG_IP1)));
+
+ arm_retx (code, ARMREG_LR);
+
+ mono_arch_flush_icache (code, code - buf);
+ g_assert (code - buf <= tramp_size);
+
+ const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline";
+ *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
+
+ return buf;
+}
+
+#else /* DISABLE_JIT */
+
+guchar*
+mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+gpointer
+mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+guint8*
+mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif /* !DISABLE_JIT */
/* Dietmar Maurer (dietmar@ximian.com) */
/* */
/* Copyright - 2001 Ximian, Inc. */
-/* */
+/* Licensed under the MIT license. See LICENSE file in the project root for full license information.*/
/*------------------------------------------------------------------*/
/*------------------------------------------------------------------*/
--- /dev/null
+/*
+ * tramp-x86-gsharedvt.c: gsharedvt support code for x86
+ *
+ * Authors:
+ * Zoltan Varga <vargaz@gmail.com>
+ *
+ * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+#include "mini.h"
+#include <mono/metadata/abi-details.h>
+
+#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
+
+gpointer
+mono_x86_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg)
+{
+ int i;
+ int *map = info->map;
+
+ /* Set vtype ret arg */
+ if (info->vret_arg_slot != -1) {
+ callee [info->vret_arg_slot] = &callee [info->vret_slot];
+ }
+ /* Copy data from the caller argument area to the callee */
+ for (i = 0; i < info->map_count; ++i) {
+ int src = map [i * 2];
+ int dst = map [i * 2 + 1];
+
+ switch ((src >> 16) & 0x3) {
+ case 0:
+ callee [dst] = caller [src];
+ break;
+ case 1: {
+ int j, nslots;
+ gpointer *arg;
+
+ /* gsharedvt->normal */
+ nslots = src >> 18;
+ arg = (gpointer*)caller [src & 0xffff];
+ for (j = 0; j < nslots; ++j)
+ callee [dst + j] = arg [j];
+ break;
+ }
+ case 2:
+ /* gsharedvt arg, have to take its address */
+ callee [dst] = caller + (src & 0xffff);
+ break;
+#if 0
+ int dst = map [i * 2 + 1];
+ if (dst >= 0xffff) {
+ /* gsharedvt arg, have to take its address */
+ callee [dst - 0xffff] = caller + map [i * 2];
+ } else {
+ callee [dst] = caller [map [i * 2]];
+ }
+#endif
+ }
+ }
+
+ if (info->vcall_offset != -1) {
+ MonoObject *this_obj = caller [0];
+
+ if (G_UNLIKELY (!this_obj))
+ return NULL;
+ if (info->vcall_offset == MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET)
+ /* delegate invoke */
+ return ((MonoDelegate*)this_obj)->invoke_impl;
+ else
+ return *(gpointer*)((char*)this_obj->vtable + info->vcall_offset);
+ } else if (info->calli) {
+ /* The address to call is passed in the mrgctx reg */
+ return mrgctx_reg;
+ } else {
+ return info->addr;
+ }
+
+}
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ guint8 *code, *buf;
+ int buf_len, cfa_offset;
+ GSList *unwind_ops = NULL;
+ MonoJumpInfo *ji = NULL;
+ guint8 *br_out, *br [16];
+ int info_offset, mrgctx_offset;
+
+ buf_len = 320;
+ buf = code = mono_global_codeman_reserve (buf_len);
+
+ /*
+ * This trampoline is responsible for marshalling calls between normal code and gsharedvt code. The
+ * caller is a normal or gshared method which uses the signature of the inflated method to make the call, while
+ * the callee is a gsharedvt method which has a signature which uses valuetypes in place of type parameters, i.e.
+ * caller:
+ * foo<bool> (bool b)
+ * callee:
+ * T=<type used to represent vtype type arguments, currently TypedByRef>
+ * foo<T> (T b)
+ * The trampoline is responsible for marshalling the arguments and marshalling the result back. To simplify
+ * things, we create our own stack frame, and do most of the work in a C function, which receives a
+ * GSharedVtCallInfo structure as an argument. The structure should contain information to execute the C function to
+ * be as fast as possible. The argument is received in EAX from a gsharedvt trampoline. So the real
+ * call sequence looks like this:
+ * caller -> gsharedvt trampoline -> gsharevt in trampoline -> start_gsharedvt_call
+ * FIXME: Optimize this.
+ */
+
+ cfa_offset = sizeof (gpointer);
+ mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, X86_NREG, -cfa_offset);
+ x86_push_reg (code, X86_EBP);
+ cfa_offset += sizeof (gpointer);
+ mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
+ mono_add_unwind_op_offset (unwind_ops, code, buf, X86_EBP, - cfa_offset);
+ x86_mov_reg_reg (code, X86_EBP, X86_ESP, sizeof (gpointer));
+ mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, X86_EBP);
+ /* Alloc stack frame/align stack */
+ x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
+ info_offset = -4;
+ mrgctx_offset = - 8;
+ /* The info struct is put into EAX by the gsharedvt trampoline */
+ /* Save info struct addr */
+ x86_mov_membase_reg (code, X86_EBP, info_offset, X86_EAX, 4);
+ /* Save rgctx */
+ x86_mov_membase_reg (code, X86_EBP, mrgctx_offset, MONO_ARCH_RGCTX_REG, 4);
+
+ /* Allocate stack area used to pass arguments to the method */
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, stack_usage), sizeof (gpointer));
+ x86_alu_reg_reg (code, X86_SUB, X86_ESP, X86_EAX);
+
+#if 0
+ /* Stack alignment check */
+ x86_mov_reg_reg (code, X86_ECX, X86_ESP, 4);
+ x86_alu_reg_imm (code, X86_AND, X86_ECX, MONO_ARCH_FRAME_ALIGNMENT - 1);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
+ x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
+ x86_breakpoint (code);
+#endif
+
+ /* ecx = caller argument area */
+ x86_mov_reg_reg (code, X86_ECX, X86_EBP, 4);
+ x86_alu_reg_imm (code, X86_ADD, X86_ECX, 8);
+ /* eax = callee argument area */
+ x86_mov_reg_reg (code, X86_EAX, X86_ESP, 4);
+
+ /* Call start_gsharedvt_call */
+ /* Arg 4 */
+ x86_push_membase (code, X86_EBP, mrgctx_offset);
+ /* Arg3 */
+ x86_push_reg (code, X86_EAX);
+ /* Arg2 */
+ x86_push_reg (code, X86_ECX);
+ /* Arg1 */
+ x86_push_membase (code, X86_EBP, info_offset);
+ if (aot) {
+ code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_x86_start_gsharedvt_call");
+ x86_call_reg (code, X86_EAX);
+ } else {
+ x86_call_code (code, mono_x86_start_gsharedvt_call);
+ }
+ x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4 * 4);
+ /* The address to call is in eax */
+ /* The stack is now setup for the real call */
+ /* Load info struct */
+ x86_mov_reg_membase (code, X86_ECX, X86_EBP, info_offset, 4);
+ /* Load rgctx */
+ x86_mov_reg_membase (code, MONO_ARCH_RGCTX_REG, X86_EBP, mrgctx_offset, sizeof (gpointer));
+ /* Make the call */
+ x86_call_reg (code, X86_EAX);
+ /* The return value is either in registers, or stored to an area beginning at sp [info->vret_slot] */
+ /* EAX/EDX might contain the return value, only ECX is free */
+ /* Load info struct */
+ x86_mov_reg_membase (code, X86_ECX, X86_EBP, info_offset, 4);
+
+ /* Branch to the in/out handling code */
+ x86_alu_membase_imm (code, X86_CMP, X86_ECX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, gsharedvt_in), 1);
+ br_out = code;
+ x86_branch32 (code, X86_CC_NE, 0, TRUE);
+
+ /*
+ * IN CASE
+ */
+
+ /* Load ret marshal type */
+ x86_mov_reg_membase (code, X86_ECX, X86_ECX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal), 4);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_NONE);
+ br [0] = code;
+ x86_branch8 (code, X86_CC_NE, 0, TRUE);
+
+ /* Normal return, no marshalling required */
+ x86_leave (code);
+ x86_ret (code);
+
+ /* Return value marshalling */
+ x86_patch (br [0], code);
+ /* Load info struct */
+ x86_mov_reg_membase (code, X86_EAX, X86_EBP, info_offset, 4);
+ /* Load 'vret_slot' */
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot), 4);
+ /* Compute ret area address */
+ x86_shift_reg_imm (code, X86_SHL, X86_EAX, 2);
+ x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_ESP);
+ /* The callee does a ret $4, so sp is off by 4 */
+ x86_alu_reg_imm (code, X86_SUB, X86_EAX, sizeof (gpointer));
+
+ /* Branch to specific marshalling code */
+ // FIXME: Move the I4 case to the top */
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_DOUBLE_FPSTACK);
+ br [1] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_FLOAT_FPSTACK);
+ br [2] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_STACK_POP);
+ br [3] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_I1);
+ br [4] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_U1);
+ br [5] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_I2);
+ br [6] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_U2);
+ br [7] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ /* IREGS case */
+ /* Load both eax and edx for simplicity */
+ x86_mov_reg_membase (code, X86_EDX, X86_EAX, sizeof (gpointer), sizeof (gpointer));
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, sizeof (gpointer));
+ x86_leave (code);
+ x86_ret (code);
+ /* DOUBLE_FPSTACK case */
+ x86_patch (br [1], code);
+ x86_fld_membase (code, X86_EAX, 0, TRUE);
+ x86_jump8 (code, 0);
+ x86_leave (code);
+ x86_ret (code);
+ /* FLOAT_FPSTACK case */
+ x86_patch (br [2], code);
+ x86_fld_membase (code, X86_EAX, 0, FALSE);
+ x86_leave (code);
+ x86_ret (code);
+ /* STACK_POP case */
+ x86_patch (br [3], code);
+ x86_leave (code);
+ x86_ret_imm (code, 4);
+ /* I1 case */
+ x86_patch (br [4], code);
+ x86_widen_membase (code, X86_EAX, X86_EAX, 0, TRUE, FALSE);
+ x86_leave (code);
+ x86_ret (code);
+ /* U1 case */
+ x86_patch (br [5], code);
+ x86_widen_membase (code, X86_EAX, X86_EAX, 0, FALSE, FALSE);
+ x86_leave (code);
+ x86_ret (code);
+ /* I2 case */
+ x86_patch (br [6], code);
+ x86_widen_membase (code, X86_EAX, X86_EAX, 0, TRUE, TRUE);
+ x86_leave (code);
+ x86_ret (code);
+ /* U2 case */
+ x86_patch (br [7], code);
+ x86_widen_membase (code, X86_EAX, X86_EAX, 0, FALSE, TRUE);
+ x86_leave (code);
+ x86_ret (code);
+
+ /*
+ * OUT CASE
+ */
+
+ x86_patch (br_out, code);
+ /* Load ret marshal type into ECX */
+ x86_mov_reg_membase (code, X86_ECX, X86_ECX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, ret_marshal), 4);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_NONE);
+ br [0] = code;
+ x86_branch8 (code, X86_CC_NE, 0, TRUE);
+
+ /* Normal return, no marshalling required */
+ x86_leave (code);
+ x86_ret (code);
+
+ /* Return value marshalling */
+ x86_patch (br [0], code);
+
+ /* EAX might contain the return value */
+ // FIXME: Use moves
+ x86_push_reg (code, X86_EAX);
+
+ /* Load info struct */
+ x86_mov_reg_membase (code, X86_EAX, X86_EBP, info_offset, 4);
+ /* Load 'vret_arg_slot' */
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_arg_slot), 4);
+ /* Compute ret area address in the caller frame in EAX */
+ x86_shift_reg_imm (code, X86_SHL, X86_EAX, 2);
+ x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_EBP);
+ x86_alu_reg_imm (code, X86_ADD, X86_EAX, 8);
+ x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, sizeof (gpointer));
+
+ /* Branch to specific marshalling code */
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_DOUBLE_FPSTACK);
+ br [1] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_FLOAT_FPSTACK);
+ br [2] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_STACK_POP);
+ br [3] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ x86_alu_reg_imm (code, X86_CMP, X86_ECX, GSHAREDVT_RET_IREGS);
+ br [4] = code;
+ x86_branch8 (code, X86_CC_E, 0, TRUE);
+ /* IREG case */
+ x86_mov_reg_reg (code, X86_ECX, X86_EAX, sizeof (gpointer));
+ x86_pop_reg (code, X86_EAX);
+ x86_mov_membase_reg (code, X86_ECX, 0, X86_EAX, sizeof (gpointer));
+ x86_leave (code);
+ x86_ret_imm (code, 4);
+ /* IREGS case */
+ x86_patch (br [4], code);
+ x86_mov_reg_reg (code, X86_ECX, X86_EAX, sizeof (gpointer));
+ x86_pop_reg (code, X86_EAX);
+ x86_mov_membase_reg (code, X86_ECX, sizeof (gpointer), X86_EDX, sizeof (gpointer));
+ x86_mov_membase_reg (code, X86_ECX, 0, X86_EAX, sizeof (gpointer));
+ x86_leave (code);
+ x86_ret_imm (code, 4);
+ /* DOUBLE_FPSTACK case */
+ x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+ x86_patch (br [1], code);
+ x86_fst_membase (code, X86_EAX, 0, TRUE, TRUE);
+ x86_jump8 (code, 0);
+ x86_leave (code);
+ x86_ret_imm (code, 4);
+ /* FLOAT_FPSTACK case */
+ x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+ x86_patch (br [2], code);
+ x86_fst_membase (code, X86_EAX, 0, FALSE, TRUE);
+ x86_leave (code);
+ x86_ret_imm (code, 4);
+ /* STACK_POP case */
+ x86_patch (br [3], code);
+ x86_leave (code);
+ x86_ret_imm (code, 4);
+
+ g_assert ((code - buf) < buf_len);
+
+ if (info)
+ *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
+
+ mono_arch_flush_icache (buf, code - buf);
+ return buf;
+}
+
+#else
+
+gpointer
+mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+ *info = NULL;
+ return NULL;
+}
+
+#endif /* MONO_ARCH_GSHAREDVT_SUPPORTED */
return buf;
}
-#if defined(ENABLE_GSHAREDVT)
-
-#include "../../../mono-extensions/mono/mini/tramp-x86-gsharedvt.c"
-
-#else
-
-gpointer
-mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
-{
- *info = NULL;
- return NULL;
-}
-
-#endif /* !MONOTOUCH */
g_free (cached);
}
-
g_free (cached_info);
+
+ for (GSList *cursor = cached_info_list; cursor != NULL; cursor = cursor->next)
+ g_free (cursor->data);
+
+ g_slist_free (cached_info_list);
}
/*
mono_memory_barrier ();
- cached_info = new_table;
-
cached_info_list = g_slist_prepend (cached_info_list, cached_info);
+ cached_info = new_table;
+
cached_info_size *= 2;
}
mono_img_writer_emit_start (w);
- xdebug_writer = mono_dwarf_writer_create (w, il_file, 0, TRUE, TRUE);
+ xdebug_writer = mono_dwarf_writer_create (w, il_file, 0, TRUE);
/* Emit something so the file has a text segment */
mono_img_writer_emit_section_change (w, ".text", 0);
if (!il_file)
il_file = fopen ("xdb.il", "w");
- dw = mono_dwarf_writer_create (w, il_file, il_file_line_index, FALSE, TRUE);
+ dw = mono_dwarf_writer_create (w, il_file, il_file_line_index, TRUE);
mono_dwarf_writer_emit_base_info (dw, "JITted code", mono_unwind_get_cie_program ());
* Alex Rønne Petersen (alexrp@xamarin.com)
*
* Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
* The AOT compiler can load these files during compilation.
* Currently, only the order in which methods were compiled is saved,
* allowing more efficient function ordering in the AOT files.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* Note: this profiler is completely unsafe wrt handling managed objects,
* don't use and don't copy code from here.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
*
* Copyright 2010 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
* Paolo Molaro (lupus@ximian.com)
*
* Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "utils.h"
#include <stdlib.h>
sgen-los.c \
sgen-major-copy-object.h \
sgen-marksweep-drain-gray-stack.h \
- sgen-marksweep-scan-object-concurrent.h \
sgen-marksweep.c \
sgen-memory-governor.c \
sgen-memory-governor.h \
sgen-pinning.h \
sgen-pointer-queue.c \
sgen-pointer-queue.h \
+ sgen-array-list.h \
+ sgen-array-list.c \
sgen-protocol-def.h \
sgen-protocol.c \
sgen-protocol.h \
*
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_METADATA_GCINTERNALAGNOSTIC_H__
* Copyright 2011 Xamarin, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGENARCHDEP_H__
#define __MONO_SGENARCHDEP_H__
--- /dev/null
+/*
+ * sgen-array-list.c: A pointer array list that doesn't require reallocs
+ *
+ * Copyright (C) 2016 Xamarin Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 2.0 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License 2.0 along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_SGEN_GC
+
+#include <string.h>
+
+#include "mono/sgen/sgen-gc.h"
+#include "mono/sgen/sgen-array-list.h"
+
+static void
+sgen_array_list_grow (SgenArrayList *array, guint32 old_capacity)
+{
+ const guint32 new_bucket = sgen_array_list_index_bucket (old_capacity);
+ const guint32 growth = sgen_array_list_bucket_size (new_bucket);
+ const guint32 new_capacity = old_capacity + growth;
+ const guint32 new_bucket_size = sizeof (**array->entries) * growth;
+ gpointer *entries;
+ if (array->capacity >= new_capacity)
+ return;
+ if (array->mem_type != -1)
+ entries = (gpointer*) sgen_alloc_internal_dynamic (new_bucket_size, array->mem_type, TRUE);
+ else
+ entries = (gpointer*) g_malloc0 (new_bucket_size);
+ if (array->bucket_alloc_callback)
+ array->bucket_alloc_callback (entries, new_bucket_size, TRUE);
+ /*
+ * The zeroing of the newly allocated bucket must be complete before storing
+ * the new bucket pointer.
+ */
+ mono_memory_write_barrier ();
+ if (InterlockedCompareExchangePointer ((volatile gpointer *)&array->entries [new_bucket], entries, NULL) == NULL) {
+ /*
+ * It must not be the case that we succeeded in setting the bucket
+ * pointer, while someone else succeeded in changing the capacity.
+ */
+ if (InterlockedCompareExchange ((volatile gint32 *)&array->capacity, new_capacity, old_capacity) != old_capacity)
+ g_assert_not_reached ();
+ array->slot_hint = old_capacity;
+ return;
+ }
+ /* Someone beat us to the allocation. */
+ if (array->bucket_alloc_callback)
+ array->bucket_alloc_callback (entries, new_bucket_size, FALSE);
+ if (array->mem_type != -1)
+ sgen_free_internal_dynamic (entries, new_bucket_size, array->mem_type);
+ else
+ g_free (entries);
+}
+
+static guint32
+sgen_array_list_find_unset (SgenArrayList *array, guint32 capacity)
+{
+ if (!array->is_slot_set_func) {
+ guint32 next_slot = array->next_slot;
+ /* We can't lookup empty slots, use next_slot */
+ if (next_slot < capacity)
+ return next_slot;
+ } else {
+ guint32 slot_hint = array->slot_hint;
+ guint32 index;
+ volatile gpointer *slot;
+
+ SGEN_ARRAY_LIST_FOREACH_SLOT_RANGE(array, slot_hint, capacity, slot, index) {
+ if (!array->is_slot_set_func (slot))
+ return index;
+ } SGEN_ARRAY_LIST_END_FOREACH_SLOT_RANGE;
+
+ SGEN_ARRAY_LIST_FOREACH_SLOT_RANGE (array, 0, slot_hint, slot, index) {
+ if (!array->is_slot_set_func (slot))
+ return index;
+ } SGEN_ARRAY_LIST_END_FOREACH_SLOT_RANGE;
+ }
+
+ return -1;
+}
+
+static void
+sgen_array_list_update_next_slot (SgenArrayList *array, guint32 new_index)
+{
+ if (!array->set_slot_func) {
+ /*
+ * If we don't have a custom setter it means we don't have thread
+ * safety requirements.
+ */
+ if (new_index >= array->next_slot)
+ array->next_slot = new_index + 1;
+ } else {
+ guint32 old_next_slot;
+ /* Thread safe update */
+ do {
+ old_next_slot = array->next_slot;
+ if (new_index < old_next_slot)
+ break;
+ } while (InterlockedCompareExchange ((volatile gint32 *)&array->next_slot, new_index + 1, old_next_slot) != old_next_slot);
+ }
+}
+
+guint32
+sgen_array_list_add (SgenArrayList *array, gpointer ptr, int data, gboolean increase_size_before_set)
+{
+ guint32 index, capacity;
+ volatile gpointer *slot;
+
+ if (!array->capacity)
+ sgen_array_list_grow (array, 0);
+retry:
+ capacity = array->capacity;
+ index = sgen_array_list_find_unset (array, capacity);
+ if (index == -1) {
+ sgen_array_list_grow (array, capacity);
+ goto retry;
+ }
+ array->slot_hint = index;
+
+ if (increase_size_before_set) {
+ sgen_array_list_update_next_slot (array, index);
+ mono_memory_write_barrier ();
+ }
+
+ slot = sgen_array_list_get_slot (array, index);
+ if (array->set_slot_func) {
+ if (!array->set_slot_func (slot, ptr, data))
+ goto retry;
+ } else {
+ *slot = ptr;
+ }
+
+ if (!increase_size_before_set) {
+ mono_memory_write_barrier ();
+ sgen_array_list_update_next_slot (array, index);
+ }
+
+ return index;
+}
+
+/*
+ * Removes all NULL pointers from the array. Not thread safe
+ */
+void
+sgen_array_list_remove_nulls (SgenArrayList *array)
+{
+ guint32 start = 0;
+ volatile gpointer *slot;
+
+ SGEN_ARRAY_LIST_FOREACH_SLOT (array, slot) {
+ if (*slot)
+ *sgen_array_list_get_slot (array, start++) = *slot;
+ } SGEN_ARRAY_LIST_END_FOREACH_SLOT;
+
+ mono_memory_write_barrier ();
+ array->next_slot = start;
+}
+
+/*
+ * Does a linear search through the pointer array to find `ptr`. Returns the index if
+ * found, otherwise (guint32)-1.
+ */
+guint32
+sgen_array_list_find (SgenArrayList *array, gpointer ptr)
+{
+ volatile gpointer *slot;
+
+ SGEN_ARRAY_LIST_FOREACH_SLOT (array, slot) {
+ if (*slot == ptr)
+ return __index;
+ } SGEN_ARRAY_LIST_END_FOREACH_SLOT;
+ return (guint32)-1;
+}
+
+#endif
--- /dev/null
+/*
+ * sgen-array-list.h: A pointer array that doesn't use reallocs.
+ *
+ * Copyright (C) 2016 Xamarin Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 2.0 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License 2.0 along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MONO_SGEN_ARRAY_LIST_H__
+#define __MONO_SGEN_ARRAY_LIST_H__
+
+#include <glib.h>
+
+#define SGEN_ARRAY_LIST_BUCKETS (32)
+#define SGEN_ARRAY_LIST_MIN_BUCKET_BITS (5)
+#define SGEN_ARRAY_LIST_MIN_BUCKET_SIZE (1 << SGEN_ARRAY_LIST_MIN_BUCKET_BITS)
+
+typedef void (*SgenArrayListBucketAllocCallback) (gpointer *bucket, guint32 new_bucket_size, gboolean alloc);
+typedef gboolean (*SgenArrayListIsSlotSetFunc) (volatile gpointer *slot);
+typedef gboolean (*SgenArrayListSetSlotFunc) (volatile gpointer *slot, gpointer ptr, int data);
+
+/*
+ * 'entries' is an array of pointers to buckets of increasing size. The first
+ * bucket has size 'MIN_BUCKET_SIZE', and each bucket is twice the size of the
+ * previous, i.e.:
+ *
+ * |-------|-- MIN_BUCKET_SIZE
+ * [0] -> xxxxxxxx
+ * [1] -> xxxxxxxxxxxxxxxx
+ * [2] -> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ * ...
+ *
+ * 'slot_hint' denotes the position of the last allocation, so that the
+ * whole array needn't be searched on every allocation.
+ *
+ * The size of the spine, 'SGEN_ARRAY_LIST_BUCKETS', is chosen so
+ * that the maximum number of entries is no less than G_MAXUINT32.
+ */
+
+typedef struct {
+ volatile gpointer *volatile entries [SGEN_ARRAY_LIST_BUCKETS];
+ volatile guint32 capacity;
+ volatile guint32 slot_hint;
+ volatile guint32 next_slot;
+ SgenArrayListBucketAllocCallback bucket_alloc_callback;
+ SgenArrayListIsSlotSetFunc is_slot_set_func;
+ SgenArrayListSetSlotFunc set_slot_func;
+ int mem_type; /* sgen internal mem type or -1 for malloc allocation */
+} SgenArrayList;
+
+/*
+ * Computes floor(log2(index + MIN_BUCKET_SIZE)) - 1, giving the index
+ * of the bucket containing a slot.
+ */
+static inline guint32
+sgen_array_list_index_bucket (guint32 index)
+{
+#ifdef __GNUC__
+ return CHAR_BIT * sizeof (index) - __builtin_clz (index + SGEN_ARRAY_LIST_MIN_BUCKET_SIZE) - 1 - SGEN_ARRAY_LIST_MIN_BUCKET_BITS;
+#else
+ guint count = 0;
+ index += SGEN_ARRAY_LIST_MIN_BUCKET_SIZE;
+ while (index) {
+ ++count;
+ index >>= 1;
+ }
+ return count - 1 - SGEN_ARRAY_LIST_MIN_BUCKET_BITS;
+#endif
+}
+
+static inline guint32
+sgen_array_list_bucket_size (guint32 index)
+{
+ return 1 << (index + SGEN_ARRAY_LIST_MIN_BUCKET_BITS);
+}
+
+static inline void
+sgen_array_list_bucketize (guint32 index, guint32 *bucket, guint32 *offset)
+{
+ *bucket = sgen_array_list_index_bucket (index);
+ *offset = index - sgen_array_list_bucket_size (*bucket) + SGEN_ARRAY_LIST_MIN_BUCKET_SIZE;
+}
+
+static inline volatile gpointer *
+sgen_array_list_get_slot (SgenArrayList *array, guint32 index)
+{
+ guint32 bucket, offset;
+
+ SGEN_ASSERT (0, index < array->capacity, "Why are we accessing an entry that is not allocated");
+
+ sgen_array_list_bucketize (index, &bucket, &offset);
+ return &(array->entries [bucket] [offset]);
+}
+
+#define SGEN_ARRAY_LIST_INIT(bucket_alloc_callback, is_slot_set_func, set_slot_func, mem_type) { { NULL }, 0, 0, 0, (bucket_alloc_callback), (is_slot_set_func), (set_slot_func), (mem_type) }
+
+#define SGEN_ARRAY_LIST_FOREACH_SLOT(array, slot) { \
+ guint32 __bucket, __offset; \
+ const guint32 __max_bucket = sgen_array_list_index_bucket ((array)->capacity); \
+ guint32 __index = 0; \
+ const guint32 __next_slot = (array)->next_slot; \
+ for (__bucket = 0; __bucket < __max_bucket; ++__bucket) { \
+ volatile gpointer *__entries = (array)->entries [__bucket]; \
+ for (__offset = 0; __offset < sgen_array_list_bucket_size (__bucket); ++__offset, ++__index) { \
+ if (__index >= __next_slot) \
+ break; \
+ slot = &__entries [__offset];
+
+#define SGEN_ARRAY_LIST_END_FOREACH_SLOT } } }
+
+#define SGEN_ARRAY_LIST_FOREACH_SLOT_RANGE(array, begin, end, slot, index) { \
+ for (index = (begin); index < (end); index++) { \
+ guint32 __bucket, __offset; \
+ volatile gpointer *__entries; \
+ sgen_array_list_bucketize (index, &__bucket, &__offset); \
+ __entries = (array)->entries [__bucket]; \
+ slot = &__entries [__offset];
+
+#define SGEN_ARRAY_LIST_END_FOREACH_SLOT_RANGE } }
+
+guint32 sgen_array_list_add (SgenArrayList *array, gpointer ptr, int data, gboolean increase_size_before_set);
+guint32 sgen_array_list_find (SgenArrayList *array, gpointer ptr);
+void sgen_array_list_remove_nulls (SgenArrayList *array);
+
+#endif
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
*out_num_cards = num_cards;
}
+/* Preclean cards and saves the cards that need to be scanned afterwards in cards_preclean */
+void
+sgen_card_table_preclean_mod_union (guint8 *cards, guint8 *cards_preclean, size_t num_cards)
+{
+ size_t i;
+
+ memcpy (cards_preclean, cards, num_cards);
+ for (i = 0; i < num_cards; i++) {
+ if (cards_preclean [i]) {
+ cards [i] = 0;
+ }
+ }
+ /*
+ * When precleaning we need to make sure the card cleaning
+ * takes place before the object is scanned. If we don't
+ * do this we could finish scanning the object and, before
+ * the cleaning of the card takes place, another thread
+ * could dirty the object, mark the mod_union card only for
+ * us to clean it back, without scanning the object again.
+ */
+ mono_memory_barrier ();
+}
+
#ifdef SGEN_HAVE_OVERLAPPING_CARDS
static void
sgen_card_table_clear_cards ();
#endif
SGEN_TV_GETTIME (atv);
- sgen_get_major_collector ()->scan_card_table (FALSE, ctx);
+ sgen_get_major_collector ()->scan_card_table (CARDTABLE_SCAN_GLOBAL, ctx);
SGEN_TV_GETTIME (btv);
last_major_scan_time = SGEN_TV_ELAPSED (atv, btv);
major_card_scan_time += last_major_scan_time;
- sgen_los_scan_card_table (FALSE, ctx);
+ sgen_los_scan_card_table (CARDTABLE_SCAN_GLOBAL, ctx);
SGEN_TV_GETTIME (atv);
last_los_scan_time = SGEN_TV_ELAPSED (btv, atv);
los_card_scan_time += last_los_scan_time;
#endif
void
-sgen_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, gboolean mod_union, ScanCopyContext ctx)
+sgen_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, ScanCopyContext ctx)
{
HEAVY_STAT (++large_objects);
- if (sgen_client_cardtable_scan_object (obj, block_obj_size, cards, mod_union, ctx))
+ if (sgen_client_cardtable_scan_object (obj, block_obj_size, cards, ctx))
return;
HEAVY_STAT (++bloby_objects);
* Copyright 2001-2003 Ximian, Inc
* Copyright 2003-2010 Novell, Inc.
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_CARD_TABLE_INLINES_H__
#define __MONO_SGEN_CARD_TABLE_INLINES_H__
void* sgen_card_table_align_pointer (void *ptr);
void sgen_card_table_mark_range (mword address, mword size);
void sgen_cardtable_scan_object (GCObject *obj, mword obj_size, guint8 *cards,
- gboolean mod_union, ScanCopyContext ctx);
+ ScanCopyContext ctx);
gboolean sgen_card_table_get_card_data (guint8 *dest, mword address, mword cards);
void sgen_card_table_update_mod_union_from_cards (guint8 *dest, guint8 *start_card, size_t num_cards);
void sgen_card_table_update_mod_union (guint8 *dest, char *obj, mword obj_size, size_t *out_num_cards);
+void sgen_card_table_preclean_mod_union (guint8 *cards, guint8 *cards_preclean, size_t num_cards);
guint8* sgen_get_card_table_configuration (int *shift_bits, gpointer *mask);
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/sgen/sgen-pointer-queue.h"
* parts of the object based on which cards are marked, do so and return TRUE. Otherwise,
* return FALSE.
*/
-gboolean sgen_client_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, gboolean mod_union, ScanCopyContext ctx);
+gboolean sgen_client_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, ScanCopyContext ctx);
/*
* Called after nursery objects have been pinned. No action is necessary.
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGENCONF_H__
#define __MONO_SGENCONF_H__
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
extern guint64 stat_copy_object_called_nursery;
* Copyright 2011 Xamarin, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#ifdef HAVE_SGEN_GC
*
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_DESCRIPTOR_H__
#define __MONO_SGEN_DESCRIPTOR_H__
* Copyright 2011 Xamarin, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2011 Xamarin, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*
* Important: allocation provides always zeroed memory, having to do
* a memset after allocation is deadly for performance.
static gboolean do_dump_nursery_content = FALSE;
static gboolean enable_nursery_canaries = FALSE;
+static gboolean precleaning_enabled = TRUE;
+
#ifdef HEAVY_STATISTICS
guint64 stat_objects_alloced_degraded = 0;
guint64 stat_bytes_alloced_degraded = 0;
* ######################################################################
*/
MonoCoopMutex gc_mutex;
-gboolean sgen_try_free_some_memory;
#define SCAN_START_SIZE SGEN_SCAN_START_SIZE
sgen_client_clear_togglerefs (start_addr, end_addr, ctx);
TV_GETTIME (btv);
- SGEN_LOG (2, "Finalize queue handling scan for %s generation: %ld usecs %d ephemeron rounds", generation_name (generation), TV_ELAPSED (atv, btv), ephemeron_rounds);
+ SGEN_LOG (2, "Finalize queue handling scan for %s generation: %lld usecs %d ephemeron rounds", generation_name (generation), TV_ELAPSED (atv, btv), ephemeron_rounds);
/*
* handle disappearing links
ScanCopyContext ctx = CONTEXT_FROM_OBJECT_OPERATIONS (job_data->ops, sgen_workers_get_job_gray_queue (worker_data));
g_assert (concurrent_collection_in_progress);
- major_collector.scan_card_table (TRUE, ctx);
+ major_collector.scan_card_table (CARDTABLE_SCAN_MOD_UNION, ctx);
}
static void
ScanCopyContext ctx = CONTEXT_FROM_OBJECT_OPERATIONS (job_data->ops, sgen_workers_get_job_gray_queue (worker_data));
g_assert (concurrent_collection_in_progress);
- sgen_los_scan_card_table (TRUE, ctx);
+ sgen_los_scan_card_table (CARDTABLE_SCAN_MOD_UNION, ctx);
+}
+
+static void
+job_mod_union_preclean (void *worker_data_untyped, SgenThreadPoolJob *job)
+{
+ WorkerData *worker_data = (WorkerData *)worker_data_untyped;
+ ScanJob *job_data = (ScanJob*)job;
+ ScanCopyContext ctx = CONTEXT_FROM_OBJECT_OPERATIONS (job_data->ops, sgen_workers_get_job_gray_queue (worker_data));
+
+ g_assert (concurrent_collection_in_progress);
+
+ major_collector.scan_card_table (CARDTABLE_SCAN_MOD_UNION_PRECLEAN, ctx);
+ sgen_los_scan_card_table (CARDTABLE_SCAN_MOD_UNION_PRECLEAN, ctx);
}
static void
TV_GETTIME (atv);
time_minor_pinning += TV_ELAPSED (btv, atv);
- SGEN_LOG (2, "Finding pinned pointers: %zd in %ld usecs", sgen_get_pinned_count (), TV_ELAPSED (btv, atv));
+ SGEN_LOG (2, "Finding pinned pointers: %zd in %lld usecs", sgen_get_pinned_count (), TV_ELAPSED (btv, atv));
SGEN_LOG (4, "Start scan with %zd pinned objects", sgen_get_pinned_count ());
sj = (ScanJob*)sgen_thread_pool_job_alloc ("scan remset", job_remembered_set_scan, sizeof (ScanJob));
/* we don't have complete write barrier yet, so we scan all the old generation sections */
TV_GETTIME (btv);
time_minor_scan_remsets += TV_ELAPSED (atv, btv);
- SGEN_LOG (2, "Old generation scan: %ld usecs", TV_ELAPSED (atv, btv));
+ SGEN_LOG (2, "Old generation scan: %lld usecs", TV_ELAPSED (atv, btv));
sgen_pin_stats_print_class_stats ();
sgen_client_binary_protocol_reclaim_end (GENERATION_NURSERY);
TV_GETTIME (btv);
time_minor_fragment_creation += TV_ELAPSED (atv, btv);
- SGEN_LOG (2, "Fragment creation: %ld usecs, %lu bytes available", TV_ELAPSED (atv, btv), (unsigned long)fragment_total);
+ SGEN_LOG (2, "Fragment creation: %lld usecs, %lu bytes available", TV_ELAPSED (atv, btv), (unsigned long)fragment_total);
if (consistency_check_at_minor_collection)
sgen_check_major_refs ();
sgen_client_pre_collection_checks ();
- if (!concurrent) {
+ if (mode != COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
/* Remsets are not useful for a major collection */
remset.clear_cards ();
}
sgen_init_pinning ();
SGEN_LOG (6, "Collecting pinned addresses");
pin_from_roots ((void*)lowest_heap_address, (void*)highest_heap_address, ctx);
-
+ if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
+ /* Pin cemented objects that were forced */
+ sgen_pin_cemented_objects ();
+ }
sgen_optimize_pin_queue ();
+ if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
+ /*
+ * Cemented objects that are in the pinned list will be marked. When
+ * marking concurrently we won't mark mod-union cards for these objects.
+ * Instead they will remain cemented until the next major collection,
+ * when we will recheck if they are still pinned in the roots.
+ */
+ sgen_cement_force_pinned ();
+ }
sgen_client_collecting_major_1 ();
TV_GETTIME (btv);
time_major_pinning += TV_ELAPSED (atv, btv);
- SGEN_LOG (2, "Finding pinned pointers: %zd in %ld usecs", sgen_get_pinned_count (), TV_ELAPSED (atv, btv));
+ SGEN_LOG (2, "Finding pinned pointers: %zd in %lld usecs", sgen_get_pinned_count (), TV_ELAPSED (atv, btv));
SGEN_LOG (4, "Start scan with %zd pinned objects", sgen_get_pinned_count ());
major_collector.init_to_space ();
- /*
- * The concurrent collector doesn't move objects, neither on
- * the major heap nor in the nursery, so we can mark even
- * before pinning has finished. For the non-concurrent
- * collector we start the workers after pinning.
- */
- if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
- SGEN_ASSERT (0, sgen_workers_all_done (), "Why are the workers not done when we start or finish a major collection?");
- sgen_workers_start_all_workers (object_ops);
- gray_queue_enable_redirect (WORKERS_DISTRIBUTE_GRAY_QUEUE);
- } else if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
+ SGEN_ASSERT (0, sgen_workers_all_done (), "Why are the workers not done when we start or finish a major collection?");
+ if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
if (sgen_workers_have_idle_work ()) {
- sgen_workers_start_all_workers (object_ops);
+ /*
+ * We force the finish of the worker with the new object ops context
+ * which can also do copying. We need to have finished pinning.
+ */
+ sgen_workers_start_all_workers (object_ops, NULL);
sgen_workers_join ();
}
}
sgen_client_collecting_major_3 (&fin_ready_queue, &critical_fin_queue);
- /*
- * FIXME: is this the right context? It doesn't seem to contain a copy function
- * unless we're concurrent.
- */
- enqueue_scan_from_roots_jobs (heap_start, heap_end, object_ops, mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT);
+ enqueue_scan_from_roots_jobs (heap_start, heap_end, object_ops, FALSE);
TV_GETTIME (btv);
time_major_scan_roots += TV_ELAPSED (atv, btv);
+ /*
+ * We start the concurrent worker after pinning and after we scanned the roots
+ * in order to make sure that the worker does not finish before handling all
+ * the roots.
+ */
+ if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
+ if (precleaning_enabled) {
+ ScanJob *sj;
+ /* Mod union preclean job */
+ sj = (ScanJob*)sgen_thread_pool_job_alloc ("preclean mod union cardtable", job_mod_union_preclean, sizeof (ScanJob));
+ sj->ops = object_ops;
+ sgen_workers_start_all_workers (object_ops, &sj->job);
+ } else {
+ sgen_workers_start_all_workers (object_ops, NULL);
+ }
+ gray_queue_enable_redirect (WORKERS_DISTRIBUTE_GRAY_QUEUE);
+ }
+
if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
ScanJob *sj;
major_finish_copy_or_mark (CopyOrMarkFromRootsMode mode)
{
if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
- /*
- * Prepare the pin queue for the next collection. Since pinning runs on the worker
- * threads we must wait for the jobs to finish before we can reset it.
- */
- sgen_workers_wait_for_jobs_finished ();
sgen_finish_pinning ();
sgen_pin_stats_reset ();
continue;
}
+ if (!strcmp (opt, "precleaning")) {
+ precleaning_enabled = TRUE;
+ continue;
+ }
+ if (!strcmp (opt, "no-precleaning")) {
+ precleaning_enabled = FALSE;
+ continue;
+ }
+
if (major_collector.handle_gc_param && major_collector.handle_gc_param (opt))
continue;
void
sgen_gc_unlock (void)
{
- gboolean try_free = sgen_try_free_some_memory;
- sgen_try_free_some_memory = FALSE;
mono_coop_mutex_unlock (&gc_mutex);
- if (try_free)
- mono_thread_hazardous_try_free_some ();
}
void
binary_protocol_world_restarted (generation, sgen_timestamp ());
- sgen_try_free_some_memory = TRUE;
-
if (sgen_client_bridge_need_processing ())
sgen_client_bridge_processing_finish (generation);
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGENGC_H__
#define __MONO_SGENGC_H__
typedef void (*CopyOrMarkObjectFunc) (GCObject**, SgenGrayQueue*);
typedef void (*ScanObjectFunc) (GCObject *obj, SgenDescriptor desc, SgenGrayQueue*);
typedef void (*ScanVTypeFunc) (GCObject *full_object, char *start, SgenDescriptor desc, SgenGrayQueue* BINARY_PROTOCOL_ARG (size_t size));
+typedef void (*ScanPtrFieldFunc) (GCObject *obj, GCObject **ptr, SgenGrayQueue* queue);
typedef gboolean (*DrainGrayStackFunc) (SgenGrayQueue *queue);
typedef struct {
CopyOrMarkObjectFunc copy_or_mark_object;
ScanObjectFunc scan_object;
ScanVTypeFunc scan_vtype;
+ ScanPtrFieldFunc scan_ptr_field;
/* Drain stack optimized for the above functions */
DrainGrayStackFunc drain_gray_stack;
/*FIXME add allocation function? */
size_t num_unique_scanned_objects;
} ScannedObjectCounts;
+typedef enum {
+ CARDTABLE_SCAN_GLOBAL = 0,
+ CARDTABLE_SCAN_MOD_UNION = 1,
+ CARDTABLE_SCAN_MOD_UNION_PRECLEAN = CARDTABLE_SCAN_MOD_UNION | 2,
+} CardTableScanType;
+
typedef struct _SgenMajorCollector SgenMajorCollector;
struct _SgenMajorCollector {
size_t section_size;
void (*free_non_pinned_object) (GCObject *obj, size_t size);
void (*pin_objects) (SgenGrayQueue *queue);
void (*pin_major_object) (GCObject *obj, SgenGrayQueue *queue);
- void (*scan_card_table) (gboolean mod_union, ScanCopyContext ctx);
+ void (*scan_card_table) (CardTableScanType scan_type, ScanCopyContext ctx);
void (*iterate_live_block_ranges) (sgen_cardtable_block_callback callback);
void (*update_cardtable_mod_union) (void);
void (*init_to_space) (void);
gboolean sgen_ptr_is_in_los (char *ptr, char **start);
void sgen_los_iterate_objects (IterateObjectCallbackFunc cb, void *user_data);
void sgen_los_iterate_live_block_ranges (sgen_cardtable_block_callback callback);
-void sgen_los_scan_card_table (gboolean mod_union, ScanCopyContext ctx);
+void sgen_los_scan_card_table (CardTableScanType scan_type, ScanCopyContext ctx);
void sgen_los_update_cardtable_mod_union (void);
void sgen_los_count_cards (long long *num_total_cards, long long *num_marked_cards);
gboolean sgen_los_is_valid_object (char *object);
*
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#include "mono/sgen/sgen-gc.h"
#include "mono/sgen/sgen-client.h"
+#include "mono/sgen/sgen-array-list.h"
#include "mono/utils/mono-membar.h"
#ifdef HEAVY_STATISTICS
static volatile guint32 stat_gc_handles_max_allocated = 0;
#endif
-#define BUCKETS (32 - MONO_GC_HANDLE_TYPE_SHIFT)
-#define MIN_BUCKET_BITS (5)
-#define MIN_BUCKET_SIZE (1 << MIN_BUCKET_BITS)
-
/*
* A table of GC handle data, implementing a simple lock-free bitmap allocator.
*
- * 'entries' is an array of pointers to buckets of increasing size. The first
- * bucket has size 'MIN_BUCKET_SIZE', and each bucket is twice the size of the
- * previous, i.e.:
- *
- * |-------|-- MIN_BUCKET_SIZE
- * [0] -> xxxxxxxx
- * [1] -> xxxxxxxxxxxxxxxx
- * [2] -> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- * ...
- *
- * The size of the spine, 'BUCKETS', is chosen so that the maximum number of
- * entries is no less than the maximum index value of a GC handle.
- *
* Each entry in a bucket is a pointer with two tag bits: if
* 'GC_HANDLE_OCCUPIED' returns true for a slot, then the slot is occupied; if
* so, then 'GC_HANDLE_VALID' gives whether the entry refers to a valid (1) or
* object pointer. If the reference is NULL, and 'GC_HANDLE_TYPE_IS_WEAK' is
* true for 'type', then the pointer is a metadata pointer--this allows us to
* retrieve the domain ID of an expired weak reference in Mono.
- *
- * Finally, 'slot_hint' denotes the position of the last allocation, so that the
- * whole array needn't be searched on every allocation.
*/
typedef struct {
- volatile gpointer *volatile entries [BUCKETS];
- volatile guint32 capacity;
- volatile guint32 slot_hint;
- volatile guint32 max_index;
+ SgenArrayList entries_array;
guint8 type;
} HandleData;
-static inline guint
-bucket_size (guint index)
-{
- return 1 << (index + MIN_BUCKET_BITS);
-}
-
-/* Computes floor(log2(index + MIN_BUCKET_SIZE)) - 1, giving the index
- * of the bucket containing a slot.
- */
-static inline guint
-index_bucket (guint index)
-{
-#ifdef __GNUC__
- return CHAR_BIT * sizeof (index) - __builtin_clz (index + MIN_BUCKET_SIZE) - 1 - MIN_BUCKET_BITS;
-#else
- guint count = 0;
- index += MIN_BUCKET_SIZE;
- while (index) {
- ++count;
- index >>= 1;
- }
- return count - 1 - MIN_BUCKET_BITS;
-#endif
-}
-
-static inline void
-bucketize (guint index, guint *bucket, guint *offset)
-{
- *bucket = index_bucket (index);
- *offset = index - bucket_size (*bucket) + MIN_BUCKET_SIZE;
-}
-
static void
protocol_gchandle_update (int handle_type, gpointer link, gpointer old_value, gpointer new_value)
{
return NULL;
}
+static inline gboolean
+is_slot_set (volatile gpointer *slot)
+{
+ gpointer entry = *slot;
+ if (MONO_GC_HANDLE_OCCUPIED (entry))
+ return TRUE;
+ return FALSE;
+}
+
/* Try to claim a slot by setting its occupied bit. */
static inline gboolean
-try_occupy_slot (HandleData *handles, guint bucket, guint offset, GCObject *obj, gboolean track)
+try_occupy_slot (volatile gpointer *slot, gpointer obj, int data)
{
- volatile gpointer *link_addr = &(handles->entries [bucket] [offset]);
- if (MONO_GC_HANDLE_OCCUPIED (*link_addr))
+ if (is_slot_set (slot))
return FALSE;
- return try_set_slot (link_addr, obj, NULL, (GCHandleType)handles->type) != NULL;
+ return try_set_slot (slot, (GCObject *)obj, NULL, (GCHandleType)data) != NULL;
+}
+
+static void
+bucket_alloc_callback (gpointer *bucket, guint32 new_bucket_size, gboolean alloc)
+{
+ if (alloc)
+ sgen_register_root ((char *)bucket, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, "pinned gc handles");
+ else
+ sgen_deregister_root ((char *)bucket);
}
static HandleData gc_handles [] = {
- { { NULL }, 0, 0, 0, (HANDLE_WEAK) },
- { { NULL }, 0, 0, 0, (HANDLE_WEAK_TRACK) },
- { { NULL }, 0, 0, 0, (HANDLE_NORMAL) },
- { { NULL }, 0, 0, 0, (HANDLE_PINNED) }
+ { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK) },
+ { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK_TRACK) },
+ { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_NORMAL) },
+ { SGEN_ARRAY_LIST_INIT (bucket_alloc_callback, is_slot_set, try_occupy_slot, -1), (HANDLE_PINNED) }
};
static HandleData *
sgen_mark_normal_gc_handles (void *addr, SgenUserMarkFunc mark_func, void *gc_data)
{
HandleData *handles = gc_handles_for_type (HANDLE_NORMAL);
- size_t bucket, offset;
- const guint max_bucket = index_bucket (handles->capacity);
- guint32 index = 0;
- const guint32 max_index = handles->max_index;
- for (bucket = 0; bucket < max_bucket; ++bucket) {
- volatile gpointer *entries = handles->entries [bucket];
- for (offset = 0; offset < bucket_size (bucket); ++offset, ++index) {
- volatile gpointer *entry;
- gpointer hidden, revealed;
- /* No need to iterate beyond the largest index ever allocated. */
- if (index > max_index)
- return;
- entry = &entries [offset];
- hidden = *entry;
- revealed = MONO_GC_REVEAL_POINTER (hidden, FALSE);
- if (!MONO_GC_HANDLE_IS_OBJECT_POINTER (hidden))
- continue;
- mark_func ((MonoObject **)&revealed, gc_data);
- g_assert (revealed);
- *entry = MONO_GC_HANDLE_OBJECT_POINTER (revealed, FALSE);
- }
- }
+ SgenArrayList *array = &handles->entries_array;
+ volatile gpointer *slot;
+ gpointer hidden, revealed;
+
+ SGEN_ARRAY_LIST_FOREACH_SLOT (array, slot) {
+ hidden = *slot;
+ revealed = MONO_GC_REVEAL_POINTER (hidden, FALSE);
+ if (!MONO_GC_HANDLE_IS_OBJECT_POINTER (hidden))
+ continue;
+ mark_func ((MonoObject **)&revealed, gc_data);
+ g_assert (revealed);
+ *slot = MONO_GC_HANDLE_OBJECT_POINTER (revealed, FALSE);
+ } SGEN_ARRAY_LIST_END_FOREACH_SLOT;
}
-static guint
-handle_data_find_unset (HandleData *handles, guint32 begin, guint32 end)
-{
- guint index;
- gint delta = begin < end ? +1 : -1;
- for (index = begin; index < end; index += delta) {
- guint bucket, offset;
- volatile gpointer *entries;
- bucketize (index, &bucket, &offset);
- entries = handles->entries [bucket];
- g_assert (entries);
- if (!MONO_GC_HANDLE_OCCUPIED (entries [offset]))
- return index;
- }
- return -1;
-}
-
-/* Adds a bucket if necessary and possible. */
-static void
-handle_data_grow (HandleData *handles, guint32 old_capacity)
-{
- const guint new_bucket = index_bucket (old_capacity);
- const guint32 growth = bucket_size (new_bucket);
- const guint32 new_capacity = old_capacity + growth;
- gpointer *entries;
- const size_t new_bucket_size = sizeof (**handles->entries) * growth;
- if (handles->capacity >= new_capacity)
- return;
- entries = (gpointer *)g_malloc0 (new_bucket_size);
- if (handles->type == HANDLE_PINNED)
- sgen_register_root ((char *)entries, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, "pinned gc handles");
- /* The zeroing of the newly allocated bucket must be complete before storing
- * the new bucket pointer.
- */
- mono_memory_write_barrier ();
- if (InterlockedCompareExchangePointer ((volatile gpointer *)&handles->entries [new_bucket], entries, NULL) == NULL) {
- /* It must not be the case that we succeeded in setting the bucket
- * pointer, while someone else succeeded in changing the capacity.
- */
- if (InterlockedCompareExchange ((volatile gint32 *)&handles->capacity, new_capacity, old_capacity) != old_capacity)
- g_assert_not_reached ();
- handles->slot_hint = old_capacity;
- return;
- }
- /* Someone beat us to the allocation. */
- if (handles->type == HANDLE_PINNED)
- sgen_deregister_root ((char *)entries);
- g_free (entries);
-}
static guint32
alloc_handle (HandleData *handles, GCObject *obj, gboolean track)
{
- guint index;
- guint32 res;
- guint bucket, offset;
- guint32 capacity;
- guint32 slot_hint;
- guint32 max_index;
- if (!handles->capacity)
- handle_data_grow (handles, 0);
-retry:
- capacity = handles->capacity;
- slot_hint = handles->slot_hint;
- index = handle_data_find_unset (handles, slot_hint, capacity);
- if (index == -1)
- index = handle_data_find_unset (handles, 0, slot_hint);
- if (index == -1) {
- handle_data_grow (handles, capacity);
- goto retry;
- }
- handles->slot_hint = index;
+ guint32 res, index;
+ SgenArrayList *array = &handles->entries_array;
/*
* If a GC happens shortly after a new bucket is allocated, the entire
* we track the maximum index seen so far, so that we can skip the empty
* slots.
*
- * Note that we update `max_index` before we even try occupying the
+ * Note that we update `next_slot` before we even try occupying the
* slot. If we did it the other way around and a GC happened in
* between, the GC wouldn't know that the slot was occupied. This is
* not a huge deal since `obj` is on the stack and thus pinned anyway,
* but hopefully some day it won't be anymore.
*/
- do {
- max_index = handles->max_index;
- if (index <= max_index)
- break;
- } while (InterlockedCompareExchange ((volatile gint32 *)&handles->max_index, index, max_index) != max_index);
-
- bucketize (index, &bucket, &offset);
- if (!try_occupy_slot (handles, bucket, offset, obj, track))
- goto retry;
+ index = sgen_array_list_add (array, obj, handles->type, TRUE);
#ifdef HEAVY_STATISTICS
InterlockedIncrement ((volatile gint32 *)&stat_gc_handles_allocated);
if (stat_gc_handles_allocated > stat_gc_handles_max_allocated)
sgen_gchandle_iterate (GCHandleType handle_type, int max_generation, SgenGCHandleIterateCallback callback, gpointer user)
{
HandleData *handle_data = gc_handles_for_type (handle_type);
- size_t bucket, offset;
- guint max_bucket = index_bucket (handle_data->capacity);
- guint32 index = 0;
- guint32 max_index = handle_data->max_index;
+ SgenArrayList *array = &handle_data->entries_array;
+ gpointer hidden, result, occupied;
+ volatile gpointer *slot;
+
/* If a new bucket has been allocated, but the capacity has not yet been
* increased, nothing can yet have been allocated in the bucket because the
* world is stopped, so we shouldn't miss any handles during iteration.
*/
- for (bucket = 0; bucket < max_bucket; ++bucket) {
- volatile gpointer *entries = handle_data->entries [bucket];
- for (offset = 0; offset < bucket_size (bucket); ++offset, ++index) {
- gpointer hidden;
- gpointer result;
- /* Table must contain no garbage pointers. */
- gboolean occupied;
- /* No need to iterate beyond the largest index ever allocated. */
- if (index > max_index)
- return;
- hidden = entries [offset];
- occupied = MONO_GC_HANDLE_OCCUPIED (hidden);
- g_assert (hidden ? occupied : !occupied);
- if (!occupied)
- continue;
- result = callback (hidden, handle_type, max_generation, user);
- if (result)
- SGEN_ASSERT (0, MONO_GC_HANDLE_OCCUPIED (result), "Why did the callback return an unoccupied entry?");
- else
- HEAVY_STAT (InterlockedDecrement ((volatile gint32 *)&stat_gc_handles_allocated));
- protocol_gchandle_update (handle_type, (gpointer)&entries [offset], hidden, result);
- entries [offset] = result;
- }
- }
+ SGEN_ARRAY_LIST_FOREACH_SLOT (array, slot) {
+ hidden = *slot;
+ occupied = (gpointer) MONO_GC_HANDLE_OCCUPIED (hidden);
+ g_assert (hidden ? !!occupied : !occupied);
+ if (!occupied)
+ continue;
+ result = callback (hidden, handle_type, max_generation, user);
+ if (result)
+ SGEN_ASSERT (0, MONO_GC_HANDLE_OCCUPIED (result), "Why did the callback return an unoccupied entry?");
+ else
+ HEAVY_STAT (InterlockedDecrement ((volatile gint32 *)&stat_gc_handles_allocated));
+ protocol_gchandle_update (handle_type, (gpointer)slot, hidden, result);
+ *slot = result;
+ } SGEN_ARRAY_LIST_END_FOREACH_SLOT;
}
/**
/* Invalid handles are possible; accessing one should produce NULL. (#34276) */
if (!handles)
return NULL;
- guint bucket, offset;
- g_assert (index < handles->capacity);
- bucketize (index, &bucket, &offset);
- return link_get (&handles->entries [bucket] [offset], MONO_GC_HANDLE_TYPE_IS_WEAK (type));
+ return link_get (sgen_array_list_get_slot (&handles->entries_array, index), MONO_GC_HANDLE_TYPE_IS_WEAK (type));
}
void
sgen_gchandle_set_target (guint32 gchandle, GCObject *obj)
{
- guint index = MONO_GC_HANDLE_SLOT (gchandle);
+ guint32 index = MONO_GC_HANDLE_SLOT (gchandle);
GCHandleType type = MONO_GC_HANDLE_TYPE (gchandle);
HandleData *handles = gc_handles_for_type (type);
+ volatile gpointer *slot;
+ gpointer entry;
+
if (!handles)
return;
- guint bucket, offset;
- gpointer slot;
- g_assert (index < handles->capacity);
- bucketize (index, &bucket, &offset);
+ slot = sgen_array_list_get_slot (&handles->entries_array, index);
do {
- slot = handles->entries [bucket] [offset];
- SGEN_ASSERT (0, MONO_GC_HANDLE_OCCUPIED (slot), "Why are we setting the target on an unoccupied slot?");
- } while (!try_set_slot (&handles->entries [bucket] [offset], obj, slot, (GCHandleType)handles->type));
+ entry = *slot;
+ SGEN_ASSERT (0, MONO_GC_HANDLE_OCCUPIED (entry), "Why are we setting the target on an unoccupied slot?");
+ } while (!try_set_slot (slot, obj, entry, (GCHandleType)handles->type));
}
static gpointer
-mono_gchandle_slot_metadata (volatile gpointer *slot_addr, gboolean is_weak)
+mono_gchandle_slot_metadata (volatile gpointer *slot, gboolean is_weak)
{
- gpointer slot;
+ gpointer entry;
gpointer metadata;
retry:
- slot = *slot_addr;
- if (!MONO_GC_HANDLE_OCCUPIED (slot))
+ entry = *slot;
+ if (!MONO_GC_HANDLE_OCCUPIED (entry))
return NULL;
- if (MONO_GC_HANDLE_IS_OBJECT_POINTER (slot)) {
- GCObject *obj = (GCObject *)MONO_GC_REVEAL_POINTER (slot, is_weak);
+ if (MONO_GC_HANDLE_IS_OBJECT_POINTER (entry)) {
+ GCObject *obj = (GCObject *)MONO_GC_REVEAL_POINTER (entry, is_weak);
/* See note [dummy use]. */
sgen_dummy_use (obj);
/*
* at this point and recompute it later, in which case we would still use
* it.
*/
- if (*slot_addr != slot)
+ if (*slot != entry)
goto retry;
return sgen_client_metadata_for_object (obj);
}
- metadata = MONO_GC_REVEAL_POINTER (slot, is_weak);
+ metadata = MONO_GC_REVEAL_POINTER (entry, is_weak);
/* See note [dummy use]. */
sgen_dummy_use (metadata);
- if (*slot_addr != slot)
+ if (*slot != entry)
goto retry;
return metadata;
}
gpointer
sgen_gchandle_get_metadata (guint32 gchandle)
{
- guint index = MONO_GC_HANDLE_SLOT (gchandle);
+ guint32 index = MONO_GC_HANDLE_SLOT (gchandle);
GCHandleType type = MONO_GC_HANDLE_TYPE (gchandle);
HandleData *handles = gc_handles_for_type (type);
+ volatile gpointer *slot;
+
if (!handles)
return NULL;
- guint bucket, offset;
- if (index >= handles->capacity)
+ if (index >= handles->entries_array.capacity)
return NULL;
- bucketize (index, &bucket, &offset);
- return mono_gchandle_slot_metadata (&handles->entries [bucket] [offset], MONO_GC_HANDLE_TYPE_IS_WEAK (type));
+
+ slot = sgen_array_list_get_slot (&handles->entries_array, index);
+
+ return mono_gchandle_slot_metadata (slot, MONO_GC_HANDLE_TYPE_IS_WEAK (type));
}
/**
void
mono_gchandle_free (guint32 gchandle)
{
- guint index = MONO_GC_HANDLE_SLOT (gchandle);
+ guint32 index = MONO_GC_HANDLE_SLOT (gchandle);
GCHandleType type = MONO_GC_HANDLE_TYPE (gchandle);
HandleData *handles = gc_handles_for_type (type);
+ volatile gpointer *slot;
+ gpointer entry;
if (!handles)
return;
- guint bucket, offset;
- gpointer slot;
- bucketize (index, &bucket, &offset);
- slot = handles->entries [bucket] [offset];
- if (index < handles->capacity && MONO_GC_HANDLE_OCCUPIED (slot)) {
- handles->entries [bucket] [offset] = NULL;
- protocol_gchandle_update (handles->type, (gpointer)&handles->entries [bucket] [offset], slot, NULL);
+
+ slot = sgen_array_list_get_slot (&handles->entries_array, index);
+ entry = *slot;
+
+ if (index < handles->entries_array.capacity && MONO_GC_HANDLE_OCCUPIED (entry)) {
+ *slot = NULL;
+ protocol_gchandle_update (handles->type, (gpointer)slot, entry, NULL);
HEAVY_STAT (InterlockedDecrement ((volatile gint32 *)&stat_gc_handles_allocated));
} else {
/* print a warning? */
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#ifdef HAVE_SGEN_GC
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_GRAY_H__
#define __MONO_SGEN_GRAY_H__
*
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
/*
* Copyright Xamarin Inc (http://www.xamarin.com)
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
/*
* Copyright Xamarin Inc (http://www.xamarin.com)
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_LAYOUT_STATS_H__
#define __MONO_SGEN_LAYOUT_STATS_H__
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
unsigned char *free_chunk_map;
};
+/* We allow read only access on the list while sweep is not running */
LOSObject *los_object_list = NULL;
mword los_memory_usage = 0;
*vtslot = vtable;
sgen_update_heap_boundaries ((mword)obj->data, (mword)obj->data + size);
obj->next = los_object_list;
+ /*
+ * We need a memory barrier so we don't expose as head of the los object list
+ * a LOSObject that doesn't have its fields initialized.
+ */
+ mono_memory_write_barrier ();
los_object_list = obj;
los_memory_usage += size;
los_num_objects++;
}
void
-sgen_los_scan_card_table (gboolean mod_union, ScanCopyContext ctx)
+sgen_los_scan_card_table (CardTableScanType scan_type, ScanCopyContext ctx)
{
LOSObject *obj;
- binary_protocol_los_card_table_scan_start (sgen_timestamp (), mod_union);
+ binary_protocol_los_card_table_scan_start (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION);
for (obj = los_object_list; obj; obj = obj->next) {
+ mword num_cards = 0;
guint8 *cards;
if (!SGEN_OBJECT_HAS_REFERENCES (obj->data))
continue;
- if (mod_union) {
+ if (scan_type & CARDTABLE_SCAN_MOD_UNION) {
if (!sgen_los_object_is_pinned (obj->data))
continue;
cards = get_cardtable_mod_union_for_object (obj);
g_assert (cards);
+ if (scan_type == CARDTABLE_SCAN_MOD_UNION_PRECLEAN) {
+ guint8 *cards_preclean;
+ mword obj_size = sgen_los_object_size (obj);
+ num_cards = sgen_card_table_number_of_cards_in_range ((mword) obj->data, obj_size);
+ cards_preclean = (guint8 *)sgen_alloc_internal_dynamic (num_cards, INTERNAL_MEM_CARDTABLE_MOD_UNION, TRUE);
+
+ sgen_card_table_preclean_mod_union (cards, cards_preclean, num_cards);
+
+ cards = cards_preclean;
+ }
} else {
cards = NULL;
}
- sgen_cardtable_scan_object (obj->data, sgen_los_object_size (obj), cards, mod_union, ctx);
+ sgen_cardtable_scan_object (obj->data, sgen_los_object_size (obj), cards, ctx);
+
+ if (scan_type == CARDTABLE_SCAN_MOD_UNION_PRECLEAN)
+ sgen_free_internal_dynamic (cards, num_cards, INTERNAL_MEM_CARDTABLE_MOD_UNION);
}
- binary_protocol_los_card_table_scan_end (sgen_timestamp (), mod_union);
+ binary_protocol_los_card_table_scan_end (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION);
}
void
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#define collector_pin_object(obj, queue) do { \
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \
} \
} else { \
- if (G_UNLIKELY (sgen_ptr_in_nursery (__old) && !sgen_ptr_in_nursery ((ptr)))) \
+ if (G_UNLIKELY (sgen_ptr_in_nursery (__old) && !sgen_ptr_in_nursery ((ptr)) && !sgen_cement_is_forced (__old))) \
mark_mod_union_card ((full_object), (void**)(ptr), __old); \
} \
} while (0)
PREFETCH_READ (__old); \
COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \
} else { \
- if (G_UNLIKELY (sgen_ptr_in_nursery (__old) && !sgen_ptr_in_nursery ((ptr)))) \
+ if (G_UNLIKELY (sgen_ptr_in_nursery (__old) && !sgen_ptr_in_nursery ((ptr)) && !sgen_cement_is_forced (__old))) \
mark_mod_union_card ((full_object), (void**)(ptr), __old); \
} \
} while (0)
#include "sgen-scan-object.h"
}
+#ifdef SCAN_VTYPE_FUNCTION_NAME
+static void
+SCAN_VTYPE_FUNCTION_NAME (GCObject *full_object, char *start, SgenDescriptor desc, SgenGrayQueue *queue BINARY_PROTOCOL_ARG (size_t size))
+{
+ SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP;
+
+#ifdef HEAVY_STATISTICS
+ /* FIXME: We're half scanning this object. How do we account for that? */
+ //add_scanned_object (start);
+#endif
+
+ /* The descriptors include info about the object header as well */
+ start -= SGEN_CLIENT_OBJECT_HEADER_SIZE;
+
+ /* We use the same HANDLE_PTR from the obj scan function */
+#define SCAN_OBJECT_NOVTABLE
+#define SCAN_OBJECT_PROTOCOL
+#include "sgen-scan-object.h"
+
+ SGEN_OBJECT_LAYOUT_STATISTICS_COMMIT_BITMAP;
+}
+#endif
+
+#ifdef SCAN_PTR_FIELD_FUNCTION_NAME
+static void
+SCAN_PTR_FIELD_FUNCTION_NAME (GCObject *full_object, GCObject **ptr, SgenGrayQueue *queue)
+{
+ HANDLE_PTR (ptr, NULL);
+}
+#endif
+
static gboolean
DRAIN_GRAY_STACK_FUNCTION_NAME (SgenGrayQueue *queue)
{
#undef COPY_OR_MARK_FUNCTION_NAME
#undef COPY_OR_MARK_WITH_EVACUATION
+#undef COPY_OR_MARK_CONCURRENT
+#undef COPY_OR_MARK_CONCURRENT_WITH_EVACUATION
#undef SCAN_OBJECT_FUNCTION_NAME
+#undef SCAN_VTYPE_FUNCTION_NAME
+#undef SCAN_PTR_FIELD_FUNCTION_NAME
#undef DRAIN_GRAY_STACK_FUNCTION_NAME
+++ /dev/null
-/*
- * sgen-major-scan-object.h: Object scanning in the major collectors.
- *
- * Copyright 2001-2003 Ximian, Inc
- * Copyright 2003-2010 Novell, Inc.
- * Copyright (C) 2012 Xamarin Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * FIXME: We use the same scanning function in the concurrent collector whether we scan
- * during the starting/finishing collection pause (with the world stopped) or from the
- * concurrent worker thread.
- *
- * As long as the world is stopped, we should just follow pointers into the nursery and
- * evict if possible. In that case we also don't need the ALWAYS_ADD_TO_GLOBAL_REMSET case,
- * which only seems to make sense for when the world is stopped, in which case we only need
- * it because we don't follow into the nursery.
- */
-
-#undef HANDLE_PTR
-#define HANDLE_PTR(ptr,obj) do { \
- GCObject *__old = *(ptr); \
- binary_protocol_scan_process_reference ((full_object), (ptr), __old); \
- if (__old) { \
- gboolean __still_in_nursery = major_copy_or_mark_object_with_evacuation ((ptr), __old, queue); \
- if (G_UNLIKELY (__still_in_nursery && !sgen_ptr_in_nursery ((ptr)) && !SGEN_OBJECT_IS_CEMENTED (*(ptr)))) { \
- GCObject *__copy = *(ptr); \
- sgen_add_to_global_remset ((ptr), __copy); \
- } \
- } \
- } while (0)
-
-
-static void
-major_scan_vtype_concurrent_finish (GCObject *full_object, char *start, SgenDescriptor desc, SgenGrayQueue *queue BINARY_PROTOCOL_ARG (size_t size))
-{
- SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP;
-
-#ifdef HEAVY_STATISTICS
- /* FIXME: We're half scanning this object. How do we account for that? */
- //add_scanned_object (start);
-#endif
-
- /* The descriptors include info about the object header as well */
- start -= SGEN_CLIENT_OBJECT_HEADER_SIZE;
-
-#define SCAN_OBJECT_NOVTABLE
-#define SCAN_OBJECT_PROTOCOL
-#include "sgen-scan-object.h"
-
- SGEN_OBJECT_LAYOUT_STATISTICS_COMMIT_BITMAP;
-}
* Copyright 2009-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#include "mono/sgen/sgen-memory-governor.h"
#include "mono/sgen/sgen-layout-stats.h"
#include "mono/sgen/sgen-pointer-queue.h"
+#include "mono/sgen/sgen-array-list.h"
#include "mono/sgen/sgen-pinning.h"
#include "mono/sgen/sgen-workers.h"
#include "mono/sgen/sgen-thread-pool.h"
#include "mono/sgen/sgen-client.h"
-#include "mono/utils/mono-membar.h"
+#include "mono/utils/mono-memory-model.h"
#if defined(ARCH_MIN_MS_BLOCK_SIZE) && defined(ARCH_MIN_MS_BLOCK_SIZE_SHIFT)
#define MS_BLOCK_SIZE ARCH_MIN_MS_BLOCK_SIZE
#define BLOCK_TAG(bl) ((bl)->has_references ? BLOCK_TAG_HAS_REFERENCES ((bl)) : (bl))
/* all allocated blocks in the system */
-static SgenPointerQueue allocated_blocks;
+static SgenArrayList allocated_blocks = SGEN_ARRAY_LIST_INIT (NULL, NULL, NULL, INTERNAL_MEM_PIN_QUEUE);
/* non-allocated block free-list */
static void *empty_blocks = NULL;
static size_t num_empty_blocks = 0;
-#define FOREACH_BLOCK_NO_LOCK_CONDITION(cond,bl) { \
- size_t __index; \
- SGEN_ASSERT (0, (cond) && !sweep_in_progress (), "Can't iterate blocks while the world is running or sweep is in progress."); \
- for (__index = 0; __index < allocated_blocks.next_slot; ++__index) { \
- (bl) = BLOCK_UNTAG (allocated_blocks.data [__index]);
-#define FOREACH_BLOCK_NO_LOCK(bl) \
- FOREACH_BLOCK_NO_LOCK_CONDITION(sgen_is_world_stopped (), bl)
+#define FOREACH_BLOCK_NO_LOCK(bl) { \
+ volatile gpointer *slot; \
+ SGEN_ASSERT (0, !sweep_in_progress (), "Can't iterate blocks while sweep is in progress."); \
+ SGEN_ARRAY_LIST_FOREACH_SLOT (&allocated_blocks, slot) { \
+ (bl) = BLOCK_UNTAG (*slot);
#define FOREACH_BLOCK_HAS_REFERENCES_NO_LOCK(bl,hr) { \
- size_t __index; \
- SGEN_ASSERT (0, sgen_is_world_stopped () && !sweep_in_progress (), "Can't iterate blocks while the world is running or sweep is in progress."); \
- for (__index = 0; __index < allocated_blocks.next_slot; ++__index) { \
- (bl) = (MSBlockInfo *)allocated_blocks.data [__index]; \
+ volatile gpointer *slot; \
+ SGEN_ASSERT (0, !sweep_in_progress (), "Can't iterate blocks while sweep is in progress."); \
+ SGEN_ARRAY_LIST_FOREACH_SLOT (&allocated_blocks, slot) { \
+ (bl) = (MSBlockInfo *) (*slot); \
(hr) = BLOCK_IS_TAGGED_HAS_REFERENCES ((bl)); \
(bl) = BLOCK_UNTAG ((bl));
-#define END_FOREACH_BLOCK_NO_LOCK } }
+#define END_FOREACH_BLOCK_NO_LOCK } SGEN_ARRAY_LIST_END_FOREACH_SLOT; }
static volatile size_t num_major_sections = 0;
/*
g_assert (block->free_list);
/* the block must be in the allocated_blocks array */
- g_assert (sgen_pointer_queue_find (&allocated_blocks, BLOCK_TAG (block)) != (size_t)-1);
+ g_assert (sgen_array_list_find (&allocated_blocks, BLOCK_TAG (block)) != (guint32)-1);
}
}
major_finish_sweep_checking ();
mono_memory_barrier ();
- sgen_pointer_queue_add (&allocated_blocks, BLOCK_TAG (info));
+ sgen_array_list_add (&allocated_blocks, BLOCK_TAG (info), 0, FALSE);
SGEN_ATOMIC_ADD_P (num_major_sections, 1);
return TRUE;
SGEN_ASSERT (0, success, "Could not set sweep state.");
}
-static gboolean ensure_block_is_checked_for_sweeping (int block_index, gboolean wait, gboolean *have_checked);
+static gboolean ensure_block_is_checked_for_sweeping (guint32 block_index, gboolean wait, gboolean *have_checked);
static SgenThreadPoolJob * volatile sweep_job;
static void
major_finish_sweep_checking (void)
{
- int block_index;
+ guint32 block_index;
SgenThreadPoolJob *job;
retry:
} else {
sgen_los_mark_mod_union_card (obj, ptr);
}
-
binary_protocol_mod_union_remset (obj, ptr, value_obj, SGEN_LOAD_VTABLE (value_obj));
}
#define COPY_OR_MARK_WITH_EVACUATION
#define COPY_OR_MARK_FUNCTION_NAME major_copy_or_mark_object_with_evacuation
#define SCAN_OBJECT_FUNCTION_NAME major_scan_object_with_evacuation
+#define SCAN_VTYPE_FUNCTION_NAME major_scan_vtype_with_evacuation
#define DRAIN_GRAY_STACK_FUNCTION_NAME drain_gray_stack_with_evacuation
+#define SCAN_PTR_FIELD_FUNCTION_NAME major_scan_ptr_field_with_evacuation
#include "sgen-marksweep-drain-gray-stack.h"
-#undef COPY_OR_MARK_WITH_EVACUATION
#define COPY_OR_MARK_CONCURRENT
#define COPY_OR_MARK_FUNCTION_NAME major_copy_or_mark_object_concurrent_no_evacuation
#define SCAN_OBJECT_FUNCTION_NAME major_scan_object_concurrent_no_evacuation
#define DRAIN_GRAY_STACK_FUNCTION_NAME drain_gray_stack_concurrent_no_evacuation
#include "sgen-marksweep-drain-gray-stack.h"
-#undef COPY_OR_MARK_CONCURRENT
#define COPY_OR_MARK_CONCURRENT_WITH_EVACUATION
#define COPY_OR_MARK_FUNCTION_NAME major_copy_or_mark_object_concurrent_with_evacuation
#define SCAN_OBJECT_FUNCTION_NAME major_scan_object_concurrent_with_evacuation
+#define SCAN_VTYPE_FUNCTION_NAME major_scan_vtype_concurrent_with_evacuation
+#define SCAN_PTR_FIELD_FUNCTION_NAME major_scan_ptr_field_concurrent_with_evacuation
#define DRAIN_GRAY_STACK_FUNCTION_NAME drain_gray_stack_concurrent_with_evacuation
#include "sgen-marksweep-drain-gray-stack.h"
return drain_gray_stack_concurrent_no_evacuation (queue);
}
-#include "sgen-marksweep-scan-object-concurrent.h"
-
static void
major_copy_or_mark_object_canonical (GCObject **ptr, SgenGrayQueue *queue)
{
* be correct, i.e. must not be used.
*/
static gboolean
-ensure_block_is_checked_for_sweeping (int block_index, gboolean wait, gboolean *have_checked)
+ensure_block_is_checked_for_sweeping (guint32 block_index, gboolean wait, gboolean *have_checked)
{
int count;
gboolean have_live = FALSE;
int i;
void *tagged_block;
MSBlockInfo *block;
+ volatile gpointer *block_slot = sgen_array_list_get_slot (&allocated_blocks, block_index);
SGEN_ASSERT (6, sweep_in_progress (), "Why do we call this function if there's no sweep in progress?");
*have_checked = FALSE;
retry:
- tagged_block = *(void * volatile *)&allocated_blocks.data [block_index];
+ tagged_block = *(void * volatile *)block_slot;
if (!tagged_block)
return FALSE;
goto retry;
}
- if (SGEN_CAS_PTR (&allocated_blocks.data [block_index], BLOCK_TAG_CHECKING (tagged_block), tagged_block) != tagged_block)
+ if (SGEN_CAS_PTR (block_slot, BLOCK_TAG_CHECKING (tagged_block), tagged_block) != tagged_block)
goto retry;
block = BLOCK_UNTAG (tagged_block);
* block list and freed.
*/
SGEN_ASSERT (6, block_index < allocated_blocks.next_slot, "How did the number of blocks shrink?");
- SGEN_ASSERT (6, allocated_blocks.data [block_index] == BLOCK_TAG_CHECKING (tagged_block), "How did the block move?");
+ SGEN_ASSERT (6, *block_slot == BLOCK_TAG_CHECKING (tagged_block), "How did the block move?");
binary_protocol_empty (MS_BLOCK_OBJ (block, 0), (char*)MS_BLOCK_OBJ (block, count) - (char*)MS_BLOCK_OBJ (block, 0));
ms_free_block (block);
}
done:
- allocated_blocks.data [block_index] = tagged_block;
+ *block_slot = tagged_block;
return !!tagged_block;
}
static void
sweep_job_func (void *thread_data_untyped, SgenThreadPoolJob *job)
{
- int block_index;
- int num_blocks = num_major_sections_before_sweep;
+ guint32 block_index;
+ guint32 num_blocks = num_major_sections_before_sweep;
SGEN_ASSERT (0, sweep_in_progress (), "Sweep thread called with wrong state");
SGEN_ASSERT (0, num_blocks <= allocated_blocks.next_slot, "How did we lose blocks?");
* cooperate with the sweep thread to finish sweeping, and they will traverse from
* low to high, to avoid constantly colliding on the same blocks.
*/
- for (block_index = num_blocks - 1; block_index >= 0; --block_index) {
- gboolean have_checked;
-
+ for (block_index = num_blocks; block_index-- > 0;) {
/*
* The block might have been freed by another thread doing some checking
* work.
*/
- if (!ensure_block_is_checked_for_sweeping (block_index, TRUE, &have_checked))
+ if (!ensure_block_is_checked_for_sweeping (block_index, TRUE, NULL))
++num_major_sections_freed_in_sweep;
}
if (SGEN_MAX_ASSERT_LEVEL >= 6) {
for (block_index = num_blocks; block_index < allocated_blocks.next_slot; ++block_index) {
- MSBlockInfo *block = BLOCK_UNTAG (allocated_blocks.data [block_index]);
+ MSBlockInfo *block = BLOCK_UNTAG (*sgen_array_list_get_slot (&allocated_blocks, block_index));
SGEN_ASSERT (6, block && block->state == BLOCK_STATE_SWEPT, "How did a new block to be swept get added while swept?");
}
}
- sgen_pointer_queue_remove_nulls (&allocated_blocks);
- mono_memory_barrier ();
+ sgen_array_list_remove_nulls (&allocated_blocks);
sweep_finish ();
*/
major_finish_sweep_checking ();
- FOREACH_BLOCK_NO_LOCK_CONDITION (TRUE, block) {
+ FOREACH_BLOCK_NO_LOCK (block) {
int count = MS_BLOCK_FREE / block->obj_size;
void **iter;
size += count * block->obj_size;
#define MS_OBJ_ALLOCED_FAST(o,b) (*(void**)(o) && (*(char**)(o) < (b) || *(char**)(o) >= (b) + MS_BLOCK_SIZE))
static void
-scan_card_table_for_block (MSBlockInfo *block, gboolean mod_union, ScanCopyContext ctx)
+scan_card_table_for_block (MSBlockInfo *block, CardTableScanType scan_type, ScanCopyContext ctx)
{
SgenGrayQueue *queue = ctx.queue;
ScanObjectFunc scan_func = ctx.ops->scan_object;
#ifndef SGEN_HAVE_OVERLAPPING_CARDS
guint8 cards_copy [CARDS_PER_BLOCK];
#endif
+ guint8 cards_preclean [CARDS_PER_BLOCK];
gboolean small_objects;
int block_obj_size;
char *block_start;
guint8 *card_data_end;
char *scan_front = NULL;
+ /* The concurrent mark doesn't enter evacuating blocks */
+ if (scan_type == CARDTABLE_SCAN_MOD_UNION_PRECLEAN && major_block_is_evacuating (block))
+ return;
+
block_obj_size = block->obj_size;
small_objects = block_obj_size < CARD_SIZE_IN_BYTES;
* Cards aliasing happens in powers of two, so as long as major blocks are aligned to their
* sizes, they won't overflow the cardtable overlap modulus.
*/
- if (mod_union) {
+ if (scan_type & CARDTABLE_SCAN_MOD_UNION) {
card_data = card_base = block->cardtable_mod_union;
/*
* This happens when the nursery collection that precedes finishing
*/
if (!card_data)
return;
+
+ if (scan_type == CARDTABLE_SCAN_MOD_UNION_PRECLEAN) {
+ sgen_card_table_preclean_mod_union (card_data, cards_preclean, CARDS_PER_BLOCK);
+ card_data = card_base = cards_preclean;
+ }
} else {
#ifdef SGEN_HAVE_OVERLAPPING_CARDS
card_data = card_base = sgen_card_table_get_card_scan_address ((mword)block_start);
if (obj < scan_front || !MS_OBJ_ALLOCED_FAST (obj, block_start))
goto next_object;
- if (mod_union) {
+ if (scan_type & CARDTABLE_SCAN_MOD_UNION) {
/* FIXME: do this more efficiently */
int w, b;
MS_CALC_MARK_BIT (w, b, obj);
scan_func (object, sgen_obj_get_descriptor (object), queue);
} else {
size_t offset = sgen_card_table_get_card_offset (obj, block_start);
- sgen_cardtable_scan_object (object, block_obj_size, card_base + offset, mod_union, ctx);
+ sgen_cardtable_scan_object (object, block_obj_size, card_base + offset, ctx);
}
next_object:
obj += block_obj_size;
}
static void
-major_scan_card_table (gboolean mod_union, ScanCopyContext ctx)
+major_scan_card_table (CardTableScanType scan_type, ScanCopyContext ctx)
{
MSBlockInfo *block;
gboolean has_references;
if (!concurrent_mark)
- g_assert (!mod_union);
+ g_assert (scan_type == CARDTABLE_SCAN_GLOBAL);
major_finish_sweep_checking ();
- binary_protocol_major_card_table_scan_start (sgen_timestamp (), mod_union);
+ binary_protocol_major_card_table_scan_start (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION);
FOREACH_BLOCK_HAS_REFERENCES_NO_LOCK (block, has_references) {
#ifdef PREFETCH_CARDS
int prefetch_index = __index + 6;
if (prefetch_index < allocated_blocks.next_slot) {
- MSBlockInfo *prefetch_block = BLOCK_UNTAG (allocated_blocks.data [prefetch_index]);
- guint8 *prefetch_cards = sgen_card_table_get_card_scan_address ((mword)MS_BLOCK_FOR_BLOCK_INFO (prefetch_block));
+ MSBlockInfo *prefetch_block = BLOCK_UNTAG (*sgen_array_list_get_slot (&allocated_blocks, prefetch_index));
PREFETCH_READ (prefetch_block);
- PREFETCH_WRITE (prefetch_cards);
- PREFETCH_WRITE (prefetch_cards + 32);
+ if (scan_type == CARDTABLE_SCAN_GLOBAL) {
+ guint8 *prefetch_cards = sgen_card_table_get_card_scan_address ((mword)MS_BLOCK_FOR_BLOCK_INFO (prefetch_block));
+ PREFETCH_WRITE (prefetch_cards);
+ PREFETCH_WRITE (prefetch_cards + 32);
+ }
}
#endif
if (!has_references)
continue;
- scan_card_table_for_block (block, mod_union, ctx);
+ scan_card_table_for_block (block, scan_type, ctx);
} END_FOREACH_BLOCK_NO_LOCK;
- binary_protocol_major_card_table_scan_end (sgen_timestamp (), mod_union);
+ binary_protocol_major_card_table_scan_end (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION);
}
static void
if (is_concurrent) {
collector->major_ops_concurrent_start.copy_or_mark_object = major_copy_or_mark_object_concurrent_canonical;
collector->major_ops_concurrent_start.scan_object = major_scan_object_concurrent_with_evacuation;
+ collector->major_ops_concurrent_start.scan_vtype = major_scan_vtype_concurrent_with_evacuation;
+ collector->major_ops_concurrent_start.scan_ptr_field = major_scan_ptr_field_concurrent_with_evacuation;
collector->major_ops_concurrent_start.drain_gray_stack = drain_gray_stack_concurrent;
collector->major_ops_concurrent_finish.copy_or_mark_object = major_copy_or_mark_object_concurrent_finish_canonical;
collector->major_ops_concurrent_finish.scan_object = major_scan_object_with_evacuation;
- collector->major_ops_concurrent_finish.scan_vtype = major_scan_vtype_concurrent_finish;
+ collector->major_ops_concurrent_finish.scan_vtype = major_scan_vtype_with_evacuation;
+ collector->major_ops_concurrent_finish.scan_ptr_field = major_scan_ptr_field_with_evacuation;
collector->major_ops_concurrent_finish.drain_gray_stack = drain_gray_stack;
}
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2001-2003 Ximian, Inc
* Copyright 2003-2010 Novell, Inc.
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_MEMORY_GOVERNOR_H__
#define __MONO_SGEN_MEMORY_GOVERNOR_H__
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#define collector_pin_object(obj, queue) sgen_pin_object (obj, queue);
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
extern guint64 stat_scan_object_called_nursery;
#include "sgen-scan-object.h"
}
+static void
+SERIAL_SCAN_PTR_FIELD (GCObject *full_object, GCObject **ptr, SgenGrayQueue *queue)
+{
+ HANDLE_PTR (ptr, NULL);
+}
+
#define FILL_MINOR_COLLECTOR_SCAN_OBJECT(collector) do { \
(collector)->serial_ops.scan_object = SERIAL_SCAN_OBJECT; \
(collector)->serial_ops.scan_vtype = SERIAL_SCAN_VTYPE; \
+ (collector)->serial_ops.scan_ptr_field = SERIAL_SCAN_PTR_FIELD; \
} while (0)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
* Copyright 2003-2010 Novell, Inc.
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
struct _CementHashEntry {
GCObject *obj;
unsigned int count;
+ gboolean forced; /* if it should stay cemented after the finishing pause */
};
static CementHashEntry cement_hash [SGEN_CEMENT_HASH_SIZE];
void
sgen_cement_reset (void)
{
- memset (cement_hash, 0, sizeof (cement_hash));
+ int i;
+ for (i = 0; i < SGEN_CEMENT_HASH_SIZE; i++) {
+ if (cement_hash [i].forced) {
+ cement_hash [i].forced = FALSE;
+ } else {
+ cement_hash [i].obj = NULL;
+ cement_hash [i].count = 0;
+ }
+ }
binary_protocol_cement_reset ();
}
+
+/*
+ * The pin_queue should be full and sorted, without entries from the cemented
+ * objects. We traverse the cement hash and check if each object is pinned in
+ * the pin_queue (the pin_queue contains entries between obj and obj+obj_len)
+ */
+void
+sgen_cement_force_pinned (void)
+{
+ int i;
+
+ if (!cement_enabled)
+ return;
+
+ for (i = 0; i < SGEN_CEMENT_HASH_SIZE; i++) {
+ GCObject *obj = cement_hash [i].obj;
+ size_t index;
+ if (!obj)
+ continue;
+ if (cement_hash [i].count < SGEN_CEMENT_THRESHOLD)
+ continue;
+ SGEN_ASSERT (0, !cement_hash [i].forced, "Why do we have a forced cemented object before forcing ?");
+
+ /* Returns the index of the target or of the first element greater than it */
+ index = sgen_pointer_queue_search (&pin_queue, obj);
+ if (index == pin_queue.next_slot)
+ continue;
+ SGEN_ASSERT (0, pin_queue.data [index] >= (gpointer)obj, "Binary search should return a pointer greater than the search target");
+ if (pin_queue.data [index] < (gpointer)((char*)obj + sgen_safe_object_get_size (obj)))
+ cement_hash [i].forced = TRUE;
+ }
+}
+
+gboolean
+sgen_cement_is_forced (GCObject *obj)
+{
+ guint hv = sgen_aligned_addr_hash (obj);
+ int i = SGEN_CEMENT_HASH (hv);
+
+ SGEN_ASSERT (5, sgen_ptr_in_nursery (obj), "Looking up cementing for non-nursery objects makes no sense");
+
+ if (!cement_enabled)
+ return FALSE;
+
+ if (!cement_hash [i].obj)
+ return FALSE;
+ if (cement_hash [i].obj != obj)
+ return FALSE;
+
+ return cement_hash [i].forced;
+}
+
gboolean
sgen_cement_lookup (GCObject *obj)
{
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_PINNING_H__
#define __MONO_SGEN_PINNING_H__
void sgen_cement_init (gboolean enabled);
void sgen_cement_reset (void);
+void sgen_cement_force_pinned (void);
+gboolean sgen_cement_is_forced (GCObject *obj);
gboolean sgen_cement_lookup (GCObject *obj);
gboolean sgen_cement_lookup_or_register (GCObject *obj);
void sgen_pin_cemented_objects (void);
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifdef HAVE_SGEN_GC
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_POINTER_QUEUE_H__
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifdef HAVE_SGEN_GC
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGENPROTOCOL_H__
*
* Copyright (C) 2013 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGENQSORT_H__
#define __MONO_SGENQSORT_H__
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2013 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*
*
* Scans one object, using the OBJ_XXX macros. The start of the
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2011-2012 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_TAGGED_POINTER_H__
*
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
static SgenThreadPoolIdleJobFunc idle_job_func;
static SgenThreadPoolContinueIdleJobFunc continue_idle_job_func;
+static volatile gboolean threadpool_shutdown;
+static volatile gboolean thread_finished;
+
enum {
STATE_WAITING,
STATE_IN_PROGRESS,
gboolean do_idle = continue_idle_job ();
SgenThreadPoolJob *job = get_job_and_set_in_progress ();
- if (!job && !do_idle) {
+ if (!job && !do_idle && !threadpool_shutdown) {
/*
* pthread_cond_wait() can return successfully despite the condition
* not being signalled, so we have to run this in a loop until we
* have to broadcast.
*/
mono_os_cond_signal (&done_cond);
- } else {
- SGEN_ASSERT (0, do_idle, "Why did we unlock if we still have to wait for idle?");
+ } else if (do_idle) {
SGEN_ASSERT (0, idle_job_func, "Why do we have idle work when there's no idle job function?");
do {
idle_job_func (thread_data);
if (!do_idle)
mono_os_cond_signal (&done_cond);
+ } else {
+ SGEN_ASSERT (0, threadpool_shutdown, "Why did we unlock if no jobs and not shutting down?");
+ mono_os_mutex_lock (&lock);
+ thread_finished = TRUE;
+ mono_os_cond_signal (&done_cond);
+ mono_os_mutex_unlock (&lock);
+ return 0;
}
}
mono_native_thread_create (&thread, thread_func, thread_datas ? thread_datas [0] : NULL);
}
+void
+sgen_thread_pool_shutdown (void)
+{
+ if (!thread)
+ return;
+
+ mono_os_mutex_lock (&lock);
+ threadpool_shutdown = TRUE;
+ mono_os_cond_signal (&work_cond);
+ while (!thread_finished)
+ mono_os_cond_wait (&done_cond, &lock);
+ mono_os_mutex_unlock (&lock);
+
+ mono_os_mutex_destroy (&lock);
+ mono_os_cond_destroy (&work_cond);
+ mono_os_cond_destroy (&done_cond);
+}
+
SgenThreadPoolJob*
sgen_thread_pool_job_alloc (const char *name, SgenThreadPoolJobFunc func, size_t size)
{
*
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_THREAD_POOL_H__
void sgen_thread_pool_init (int num_threads, SgenThreadPoolThreadInitFunc init_func, SgenThreadPoolIdleJobFunc idle_func, SgenThreadPoolContinueIdleJobFunc continue_idle_func, void **thread_datas);
+void sgen_thread_pool_shutdown (void);
+
SgenThreadPoolJob* sgen_thread_pool_job_alloc (const char *name, SgenThreadPoolJobFunc func, size_t size);
/* This only needs to be called on jobs that are not enqueued. */
void sgen_thread_pool_job_free (SgenThreadPoolJob *job);
* Copyright 2003-2010 Novell, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
static volatile State workers_state;
static SgenObjectOperations * volatile idle_func_object_ops;
+static SgenThreadPoolJob * volatile preclean_job;
static guint64 stat_workers_num_finished;
sgen_drain_gray_stack (ctx);
} else {
- worker_try_finish ();
+ SgenThreadPoolJob *job = preclean_job;
+ if (job) {
+ sgen_thread_pool_job_enqueue (job);
+ preclean_job = NULL;
+ } else {
+ worker_try_finish ();
+ }
}
}
void
sgen_workers_stop_all_workers (void)
{
+ preclean_job = NULL;
+ mono_memory_write_barrier ();
forced_stop = TRUE;
sgen_thread_pool_wait_for_all_jobs ();
}
void
-sgen_workers_start_all_workers (SgenObjectOperations *object_ops)
+sgen_workers_start_all_workers (SgenObjectOperations *object_ops, SgenThreadPoolJob *job)
{
forced_stop = FALSE;
idle_func_object_ops = object_ops;
+ preclean_job = job;
mono_memory_write_barrier ();
sgen_workers_ensure_awake ();
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SGEN_WORKER_H__
void sgen_workers_init (int num_workers);
void sgen_workers_stop_all_workers (void);
-void sgen_workers_start_all_workers (SgenObjectOperations *object_ops);
+void sgen_workers_start_all_workers (SgenObjectOperations *object_ops, SgenThreadPoolJob *finish_job);
void sgen_workers_ensure_awake (void);
void sgen_workers_init_distribute_gray_queue (void);
void sgen_workers_enqueue_job (SgenThreadPoolJob *job, gboolean enqueue);
$(ILASM) -out:$@ $<
%.exe: %.cs TestDriver.dll
- $(MCS) -r:System.dll -r:System.Xml.dll -r:System.Core.dll -r:TestDriver.dll -out:$@ $<
+ $(MCS) -r:System.dll -r:System.Xml.dll -r:System.Core.dll -r:TestDriver.dll -r:Mono.Posix.dll -out:$@ $<
# mkbundle works on ppc, but the pkg-config POC doesn't when run with make test
if POWERPC
public class Tests
{
public static int Main(string[] args) {
- return TestDriver.RunTests (typeof (Tests), args);
+ if (args.Length == 0)
+ return TestDriver.RunTests (typeof (Tests), new String[] { "-v" });
+ else
+ return TestDriver.RunTests (typeof (Tests), args);
}
public static int test_0_unload () {
return del (42);
}
+typedef char* (STDCALL *IcallDelegate) (const char *);
+LIBTEST_API int STDCALL
+mono_test_marshal_icall_delegate (IcallDelegate del)
+{
+ char *res = del ("ABC");
+ return strcmp (res, "ABC") == 0 ? 0 : 1;
+}
+
LIBTEST_API int STDCALL
mono_test_marshal_stringbuilder (char *s, int n)
{
//
// Copyright 2011 Xamarin Inc (http://www.xamarin.com).
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
[DllImport ("libtest", EntryPoint="mono_test_marshal_virtual_delegate")]
public static extern int mono_test_marshal_virtual_delegate (VirtualDelegate del);
+ [DllImport ("libtest", EntryPoint="mono_test_marshal_icall_delegate")]
+ public static extern int mono_test_marshal_icall_delegate (IcallDelegate del);
+
+ public delegate string IcallDelegate (IntPtr p);
+
public delegate int TestDelegate (int a, ref SimpleStruct ss, int b);
public delegate SimpleStruct SimpleDelegate2 (SimpleStruct ss);
return mono_test_marshal_virtual_delegate (b.get_del ());
}
+
+ public static int test_0_icall_delegate () {
+ var m = typeof (Marshal).GetMethod ("PtrToStringAnsi", new Type[] { typeof (IntPtr) });
+
+ return mono_test_marshal_icall_delegate ((IcallDelegate)Delegate.CreateDelegate (typeof (IcallDelegate), m));
+ }
}
//
// Bill Seurer (seurer@linux.vnet.ibm.com)
//
-// (C) {Copyright holder}
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
//
// Bill Seurer (seurer@linux.vnet.ibm.com)
//
-// (C) {Copyright holder}
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
//
// Bill Seurer (seurer@linux.vnet.ibm.com)
//
-// (C) {Copyright holder}
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
//
// Bill Seurer (seurer@linux.vnet.ibm.com)
//
-// (C) {Copyright holder}
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
//
// Bill Seurer (seurer@linux.vnet.ibm.com)
//
-// (C) {Copyright holder}
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
//
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
//
-// 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.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.IO;
using System.Globalization;
using System.Xml;
using System.Text.RegularExpressions;
+using Mono.Unix.Native;
//
// This is a simple test runner with support for parallel execution
timedout.Add (data);
}
+ // Force the process to print a thread dump
+ try {
+ Syscall.kill (p.Id, Signum.SIGQUIT);
+ Thread.Sleep (1000);
+ } catch {
+ }
+
output.Write ("timed out");
p.Kill ();
//
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
//
-// 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.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.//
//
using System;
using System.IO;
//
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
//
-// 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.
-//
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.IO;
using System.Reflection;
+++ /dev/null
-These CLI bytecode verifier tests are licensed under the
-terms of the GNU Library General Public License, version 2.
-
- GNU LIBRARY GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the library GPL. It is
- numbered 2 because it goes with version 2 of the ordinary GPL.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Library General Public License, applies to some
-specially designated Free Software Foundation software, and to any
-other libraries whose authors decide to use it. You can use it for
-your libraries, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if
-you distribute copies of the library, or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link a program with the library, you must provide
-complete object files to the recipients so that they can relink them
-with the library, after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- Our method of protecting your rights has two steps: (1) copyright
-the library, and (2) offer you this license which gives you legal
-permission to copy, distribute and/or modify the library.
-
- Also, for each distributor's protection, we want to make certain
-that everyone understands that there is no warranty for this free
-library. If the library is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original
-version, so that any problems introduced by others will not reflect on
-the original authors' reputations.
-\f
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that companies distributing free
-software will individually obtain patent licenses, thus in effect
-transforming the program into proprietary software. To prevent this,
-we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
- Most GNU software, including some libraries, is covered by the ordinary
-GNU General Public License, which was designed for utility programs. This
-license, the GNU Library General Public License, applies to certain
-designated libraries. This license is quite different from the ordinary
-one; be sure to read it in full, and don't assume that anything in it is
-the same as in the ordinary license.
-
- The reason we have a separate public license for some libraries is that
-they blur the distinction we usually make between modifying or adding to a
-program and simply using it. Linking a program with a library, without
-changing the library, is in some sense simply using the library, and is
-analogous to running a utility program or application program. However, in
-a textual and legal sense, the linked executable is a combined work, a
-derivative of the original library, and the ordinary General Public License
-treats it as such.
-
- Because of this blurred distinction, using the ordinary General
-Public License for libraries did not effectively promote software
-sharing, because most developers did not use the libraries. We
-concluded that weaker conditions might promote sharing better.
-
- However, unrestricted linking of non-free programs would deprive the
-users of those programs of all benefit from the free status of the
-libraries themselves. This Library General Public License is intended to
-permit developers of non-free programs to use free libraries, while
-preserving your freedom as a user of such programs to change the free
-libraries that are incorporated in them. (We have not seen how to achieve
-this as regards changes in header files, but we have achieved it as regards
-changes in the actual functions of the Library.) The hope is that this
-will lead to faster development of free libraries.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, while the latter only
-works together with the library.
-
- Note that it is possible for a library to be covered by the ordinary
-General Public License rather than by this special one.
-\f
- GNU LIBRARY GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library which
-contains a notice placed by the copyright holder or other authorized
-party saying it may be distributed under the terms of this Library
-General Public License (also called "this License"). Each licensee is
-addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-\f
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-\f
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-\f
- 6. As an exception to the Sections above, you may also compile or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- c) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- d) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the source code distributed need not include anything that is normally
-distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-\f
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-\f
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Library General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-\f
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-\f
- Appendix: How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
*
* Copyright (C) 2013 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Aleksey Kliger <aleksey@xamarin.com>
*
* Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* Copyright (C) 2013 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#elif defined (HAVE_64BIT_CMPXCHG_FALLBACK)
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/utils/atomic.c"
+#if defined (TARGET_IOS) || defined (TARGET_WATCHOS)
+
+#ifndef __clang__
+#error "Not supported."
+#endif
+
+gint64
+InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
+{
+ return __sync_val_compare_and_swap (dest, comp, exch);
+}
+
+#elif defined (TARGET_ANDROID)
+
+/* Some Android systems can't find the 64-bit CAS intrinsic at runtime,
+ * so we have to roll our own...
+ */
+
+gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp) __attribute__ ((naked));
+
+gint64
+InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
+{
+ __asm__ (
+ "push {r4, r5, r6, r7}\n"
+ "ldrd r4, [sp, #16]\n"
+ "dmb sy\n"
+ "1:\n"
+ "ldrexd r6, [r0]\n"
+ "cmp r7, r5\n"
+ "cmpeq r6, r4\n"
+ "bne 2f\n"
+ "strexd r1, r2, [r0]\n"
+ "cmp r1, #0\n"
+ "bne 1b\n"
+ "2:\n"
+ "dmb sy\n"
+ "mov r0, r6\n"
+ "mov r1, r7\n"
+ "pop {r4, r5, r6, r7}\n"
+ "bx lr\n"
+ );
+}
+
+#else
+
+#error "Need a 64-bit CAS fallback!"
+
#endif
#else
*
* (C) 2002 Ximian, Inc.
* Copyright 2012 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef _WAPI_ATOMIC_H_
#include "config.h"
#include <glib.h>
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/utils/atomic.h"
+/*
+The current Nexus 7 arm-v7a fails with:
+F/MonoDroid( 1568): shared runtime initialization error: Cannot load library: reloc_library[1285]: 37 cannot locate '__sync_val_compare_and_swap_8'
+
+Apple targets have historically being problematic, xcode 4.6 would miscompile the intrinsic.
+*/
+
+#if defined (__arm__) && defined (HAVE_ARMV7)
+#define HAVE_64BIT_CMPXCHG_FALLBACK /* See atomic.c in this directory. */
#endif
/* On Windows, we always use the functions provided by the Windows API. */
*/
#include <config.h>
-#ifdef CHECKED_BUILD
+#ifdef ENABLE_CHECKED_BUILD
#include <mono/utils/checked-build.h>
#include <mono/utils/mono-threads.h>
#include <execinfo.h>
#endif
+// Selective-enable support
+
+// Returns true for check modes which are allowed by both the current DISABLE_ macros and the MONO_CHECK_MODE env var.
+// Argument may be a bitmask; if so, result is true if at least one specified mode is enabled.
+mono_bool
+mono_check_mode_enabled (MonoCheckMode query)
+{
+ static MonoCheckMode check_mode = MONO_CHECK_MODE_UNKNOWN;
+ if (G_UNLIKELY (check_mode == MONO_CHECK_MODE_UNKNOWN))
+ {
+ MonoCheckMode env_check_mode = MONO_CHECK_MODE_NONE;
+ const gchar *env_string = g_getenv ("MONO_CHECK_MODE");
+
+ if (env_string)
+ {
+ gchar **env_split = g_strsplit (env_string, ",", 0);
+ for (gchar **env_component = env_split; *env_component; env_component++)
+ {
+ mono_bool check_all = g_str_equal (*env_component, "all");
+#ifdef ENABLE_CHECKED_BUILD_GC
+ if (check_all || g_str_equal (*env_component, "gc"))
+ env_check_mode |= MONO_CHECK_MODE_GC;
+#endif
+#ifdef ENABLE_CHECKED_BUILD_METADATA
+ if (check_all || g_str_equal (*env_component, "metadata"))
+ env_check_mode |= MONO_CHECK_MODE_METADATA;
+#endif
+#ifdef ENABLE_CHECKED_BUILD_THREAD
+ if (check_all || g_str_equal (*env_component, "thread"))
+ env_check_mode |= MONO_CHECK_MODE_THREAD;
+#endif
+ }
+ g_strfreev (env_split);
+ }
+
+ check_mode = env_check_mode;
+ }
+ return check_mode & query;
+}
+
+static int
+mono_check_transition_limit (void)
+{
+ static int transition_limit = -1;
+ if (transition_limit < 0) {
+ const gchar *env_string = g_getenv ("MONO_CHECK_THREAD_TRANSITION_HISTORY");
+ if (env_string)
+ transition_limit = atoi (env_string);
+ else
+ transition_limit = 3;
+ }
+ return transition_limit;
+}
+
typedef struct {
GPtrArray *transitions;
guint32 in_gc_critical_region;
void
checked_build_init (void)
{
- mono_native_tls_alloc (&thread_status, NULL);
+ // Init state for get_state, which can be called either by gc or thread mode
+ if (mono_check_mode_enabled (MONO_CHECK_MODE_GC | MONO_CHECK_MODE_THREAD))
+ mono_native_tls_alloc (&thread_status, NULL);
}
static CheckState*
return state;
}
-#if !defined(DISABLE_CHECKED_BUILD_THREAD)
+#ifdef ENABLE_CHECKED_BUILD_THREAD
#define MAX_NATIVE_BT 6
#define MAX_NATIVE_BT_PROBE (MAX_NATIVE_BT + 5)
-#define MAX_TRANSITIONS 3
+#define MAX_TRANSITIONS (mono_check_transition_limit ())
#ifdef HAVE_BACKTRACE_SYMBOLS
void
checked_build_thread_transition (const char *transition, void *info, int from_state, int suspend_count, int next_state, int suspend_count_delta)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_THREAD))
+ return;
+
MonoThreadInfo *cur = mono_thread_info_current_unchecked ();
CheckState *state = get_state ();
/* We currently don't record external changes as those are hard to reason about. */
g_ptr_array_add (state->transitions, t);
}
-#endif /* !defined(DISABLE_CHECKED_BUILD_THREAD) */
-
-#if !defined(DISABLE_CHECKED_BUILD_GC)
-
-static void
-assertion_fail (const char *msg, ...)
+void
+mono_fatal_with_history (const char *msg, ...)
{
int i;
GString* err = g_string_sized_new (100);
- CheckState *state = get_state ();
g_string_append_printf (err, "Assertion failure in thread %p due to: ", mono_native_thread_id_get ());
g_string_append_vprintf (err, msg, args);
va_end (args);
- g_string_append_printf (err, "\nLast %d state transitions: (most recent first)\n", state->transitions->len);
-
- for (i = state->transitions->len - 1; i >= 0; --i) {
- ThreadTransition *t = state->transitions->pdata [i];
- char *bt = translate_backtrace (t->backtrace, t->size);
- g_string_append_printf (err, "[%s] %s -> %s (%d) %s%d at:\n%s",
- t->name,
- mono_thread_state_name (t->from_state),
- mono_thread_state_name (t->next_state),
- t->suspend_count,
- t->suspend_count_delta > 0 ? "+" : "", //I'd like to see this sort of values: -1, 0, +1
- t->suspend_count_delta,
- bt);
- g_free (bt);
+ if (mono_check_mode_enabled (MONO_CHECK_MODE_THREAD))
+ {
+ CheckState *state = get_state ();
+
+ g_string_append_printf (err, "\nLast %d state transitions: (most recent first)\n", state->transitions->len);
+
+ for (i = state->transitions->len - 1; i >= 0; --i) {
+ ThreadTransition *t = state->transitions->pdata [i];
+ char *bt = translate_backtrace (t->backtrace, t->size);
+ g_string_append_printf (err, "[%s] %s -> %s (%d) %s%d at:\n%s",
+ t->name,
+ mono_thread_state_name (t->from_state),
+ mono_thread_state_name (t->next_state),
+ t->suspend_count,
+ t->suspend_count_delta > 0 ? "+" : "", //I'd like to see this sort of values: -1, 0, +1
+ t->suspend_count_delta,
+ bt);
+ g_free (bt);
+ }
}
g_error (err->str);
g_string_free (err, TRUE);
}
+#endif /* defined(ENABLE_CHECKED_BUILD_THREAD) */
+
+#ifdef ENABLE_CHECKED_BUILD_GC
+
void
assert_gc_safe_mode (void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
MonoThreadInfo *cur = mono_thread_info_current ();
int state;
if (!cur)
- assertion_fail ("Expected GC Safe mode but thread is not attached");
+ mono_fatal_with_history ("Expected GC Safe mode but thread is not attached");
switch (state = mono_thread_info_current_state (cur)) {
case STATE_BLOCKING:
case STATE_BLOCKING_AND_SUSPENDED:
break;
default:
- assertion_fail ("Expected GC Safe mode but was in %s state", mono_thread_state_name (state));
+ mono_fatal_with_history ("Expected GC Safe mode but was in %s state", mono_thread_state_name (state));
}
}
void
assert_gc_unsafe_mode (void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
MonoThreadInfo *cur = mono_thread_info_current ();
int state;
if (!cur)
- assertion_fail ("Expected GC Unsafe mode but thread is not attached");
+ mono_fatal_with_history ("Expected GC Unsafe mode but thread is not attached");
switch (state = mono_thread_info_current_state (cur)) {
case STATE_RUNNING:
case STATE_SELF_SUSPEND_REQUESTED:
break;
default:
- assertion_fail ("Expected GC Unsafe mode but was in %s state", mono_thread_state_name (state));
+ mono_fatal_with_history ("Expected GC Unsafe mode but was in %s state", mono_thread_state_name (state));
}
}
void
assert_gc_neutral_mode (void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
MonoThreadInfo *cur = mono_thread_info_current ();
int state;
if (!cur)
- assertion_fail ("Expected GC Neutral mode but thread is not attached");
+ mono_fatal_with_history ("Expected GC Neutral mode but thread is not attached");
switch (state = mono_thread_info_current_state (cur)) {
case STATE_RUNNING:
case STATE_BLOCKING_AND_SUSPENDED:
break;
default:
- assertion_fail ("Expected GC Neutral mode but was in %s state", mono_thread_state_name (state));
+ mono_fatal_with_history ("Expected GC Neutral mode but was in %s state", mono_thread_state_name (state));
}
}
void *
critical_gc_region_begin(void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return NULL;
+
CheckState *state = get_state ();
state->in_gc_critical_region++;
return state;
void
critical_gc_region_end(void* token)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
CheckState *state = get_state();
g_assert (state == token);
state->in_gc_critical_region--;
void
assert_not_in_gc_critical_region(void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
CheckState *state = get_state();
if (state->in_gc_critical_region > 0) {
- assertion_fail("Expected GC Unsafe mode, but was in %s state", mono_thread_state_name (mono_thread_info_current_state (mono_thread_info_current ())));
+ mono_fatal_with_history("Expected GC Unsafe mode, but was in %s state", mono_thread_state_name (mono_thread_info_current_state (mono_thread_info_current ())));
}
}
void
assert_in_gc_critical_region (void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
CheckState *state = get_state();
if (state->in_gc_critical_region == 0)
- assertion_fail("Expected GC critical region");
+ mono_fatal_with_history("Expected GC critical region");
}
-#endif /* !defined(DISABLE_CHECKED_BUILD_GC) */
+#endif /* defined(ENABLE_CHECKED_BUILD_GC) */
-#if !defined(DISABLE_CHECKED_BUILD_METADATA)
+#ifdef ENABLE_CHECKED_BUILD_METADATA
// check_metadata_store et al: The goal of these functions is to verify that if there is a pointer from one mempool into
// another, that the pointed-to memory is protected by the reference count mechanism for MonoImages.
static void
check_mempool_may_reference_mempool (void *from_ptr, void *to_ptr, gboolean require_local)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_METADATA))
+ return;
+
// Null pointers are OK
if (!to_ptr)
return;
check_mempool_may_reference_mempool (from, to, TRUE);
}
-#endif /* !defined(DISABLE_CHECKED_BUILD_METADATA) */
+#endif /* defined(ENABLE_CHECKED_BUILD_METADATA) */
-#endif /* CHECKED_BUILD */
+#endif /* ENABLE_CHECKED_BUILD */
#include <config.h>
#include <mono/utils/atomic.h>
+#include <mono/utils/mono-publib.h>
+
+typedef enum {
+ MONO_CHECK_MODE_NONE = 0,
+ MONO_CHECK_MODE_GC = 0x1,
+ MONO_CHECK_MODE_METADATA = 0x2,
+ MONO_CHECK_MODE_THREAD = 0x4,
+ MONO_CHECK_MODE_ALL = MONO_CHECK_MODE_GC | MONO_CHECK_MODE_METADATA | MONO_CHECK_MODE_THREAD,
+ MONO_CHECK_MODE_UNKNOWN = 0x8
+} MonoCheckMode;
+
+mono_bool mono_check_mode_enabled (MonoCheckMode query);
// This is for metadata writes which we have chosen not to check at the current time.
// Because in principle this should never happen, we still use a macro so that the exemptions will be easier to find, and remove, later.
// The current reason why this is needed is for pointers to constant strings, which the checker cannot verify yet.
#define CHECKED_METADATA_WRITE_PTR_EXEMPT(ptr, val) do { (ptr) = (val); } while (0)
-#if defined(CHECKED_BUILD)
+#ifdef ENABLE_CHECKED_BUILD
#define g_assert_checked g_assert
#define CHECKED_MONO_INIT()
-#endif /* CHECKED_BUILD */
-
-#if defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_GC)
+#endif /* ENABLE_CHECKED_BUILD */
+#ifdef ENABLE_CHECKED_BUILD_GC
/*
GC runtime modes rules:
#define MONO_REQ_GC_NOT_CRITICAL
#define MONO_REQ_GC_CRITICAL
-#endif /* defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_GC) */
+#endif /* defined(ENABLE_CHECKED_BUILD_GC) */
-#if defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_METADATA)
+#ifdef ENABLE_CHECKED_BUILD_METADATA
// Use when writing a pointer from one image or imageset to another.
#define CHECKED_METADATA_WRITE_PTR(ptr, val) do { \
#define CHECKED_METADATA_WRITE_PTR_LOCAL(ptr, val) do { (ptr) = (val); } while (0)
#define CHECKED_METADATA_WRITE_PTR_ATOMIC(ptr, val) do { mono_atomic_store_release (&(ptr), (val)); } while (0)
-#endif /* defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_METADATA) */
+#endif /* defined(ENABLE_CHECKED_BUILD_METADATA) */
-#if defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_THREAD)
+#ifdef ENABLE_CHECKED_BUILD_THREAD
#define CHECKED_BUILD_THREAD_TRANSITION(transition, info, from_state, suspend_count, next_state, suspend_count_delta) do { \
checked_build_thread_transition (transition, info, from_state, suspend_count, next_state, suspend_count_delta); \
void checked_build_thread_transition(const char *transition, void *info, int from_state, int suspend_count, int next_state, int suspend_count_delta);
+void mono_fatal_with_history(const char *msg, ...);
+
#else
#define CHECKED_BUILD_THREAD_TRANSITION(transition, info, from_state, suspend_count, next_state, suspend_count_delta)
-#endif /* defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_THREAD) */
+#define mono_fatal_with_history g_error
+
+#endif /* defined(ENABLE_CHECKED_BUILD_THREAD) */
#endif /* __CHECKED_BUILD_H__ */
#define dlindependent_comalloc independent_comalloc
#endif /* USE_DL_PREFIX */
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/utils/dlmalloc.h"
-#endif
+#define dlcalloc mono_dlcalloc
+#define dlfree mono_dlfree
+#define dlmalloc mono_dlmalloc
+#define dlmemalign mono_dlmemalign
+#define dlrealloc mono_dlrealloc
+#define dlvalloc mono_dlvalloc
+#define dlpvalloc mono_dlpvalloc
+#define dlmallinfo mono_dlmallinfo
+#define dlmallopt mono_dlmallopt
+#define dlmalloc_trim mono_dlmalloc_trim
+#define dlmalloc_stats mono_dlmalloc_stats
+#define dlmalloc_usable_size mono_dlmalloc_usable_size
+#define dlmalloc_footprint mono_dlmalloc_footprint
+#define dlindependent_calloc mono_dlindependent_calloc
+#define dlindependent_comalloc mono_dlindependent_comalloc
/*
malloc(size_t n)
/*
* Copyright 2004-2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_OS_GC_WRAPPER_H__
#define __MONO_OS_GC_WRAPPER_H__
* hazard-pointer.c: Hazard pointer related code.
*
* (C) Copyright 2011 Novell, Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
static volatile int hazard_table_size = 0;
static MonoThreadHazardPointers * volatile hazard_table = NULL;
+static MonoHazardFreeQueueSizeCallback queue_size_cb;
/*
* Each entry is either 0 or 1, indicating whether that overflow small
return TRUE;
}
+/**
+ * mono_thread_hazardous_try_free:
+ * @p: the pointer to free
+ * @free_func: the function that can free the pointer
+ *
+ * If @p is not a hazardous pointer it will be immediately freed by calling @free_func.
+ * Otherwise it will be queued for later.
+ *
+ * Use this function if @free_func can ALWAYS be called in the context where this function is being called.
+ *
+ * This function doesn't pump the free queue so try to accommodate a call at an appropriate time.
+ * See mono_thread_hazardous_try_free_some for when it's appropriate.
+ *
+ * Return: TRUE if @p was free or FALSE if it was queued.
+ */
+gboolean
+mono_thread_hazardous_try_free (gpointer p, MonoHazardousFreeFunc free_func)
+{
+ if (!is_pointer_hazardous (p)) {
+ free_func (p);
+ return TRUE;
+ } else {
+ mono_thread_hazardous_queue_free (p, free_func);
+ return FALSE;
+ }
+}
+
+/**
+ * mono_thread_hazardous_queue_free:
+ * @p: the pointer to free
+ * @free_func: the function that can free the pointer
+ *
+ * Queue @p to be freed later. @p will be freed once the hazard free queue is pumped.
+ *
+ * This function doesn't pump the free queue so try to accommodate a call at an appropriate time.
+ * See mono_thread_hazardous_try_free_some for when it's appropriate.
+ *
+ */
void
-mono_thread_hazardous_free_or_queue (gpointer p, MonoHazardousFreeFunc free_func,
- HazardFreeLocking locking, HazardFreeContext context)
+mono_thread_hazardous_queue_free (gpointer p, MonoHazardousFreeFunc free_func)
{
- int i;
+ DelayedFreeItem item = { p, free_func, HAZARD_FREE_MAY_LOCK };
- /* First try to free a few entries in the delayed free
- table. */
- for (i = 0; i < 3; ++i)
- try_free_delayed_free_item (context);
+ InterlockedIncrement (&hazardous_pointer_count);
- /* Now see if the pointer we're freeing is hazardous. If it
- isn't, free it. Otherwise put it in the delay list. */
- if ((context == HAZARD_FREE_ASYNC_CTX && locking == HAZARD_FREE_MAY_LOCK) ||
- is_pointer_hazardous (p)) {
- DelayedFreeItem item = { p, free_func, locking };
+ mono_lock_free_array_queue_push (&delayed_free_queue, &item);
- ++hazardous_pointer_count;
+ guint32 queue_size = delayed_free_queue.num_used_entries;
+ if (queue_size && queue_size_cb)
+ queue_size_cb (queue_size);
+}
- mono_lock_free_array_queue_push (&delayed_free_queue, &item);
- } else {
- free_func (p);
- }
+
+void
+mono_hazard_pointer_install_free_queue_size_callback (MonoHazardFreeQueueSizeCallback cb)
+{
+ queue_size_cb = cb;
}
void
* hazard-pointer.h: Hazard pointer related code.
*
* (C) Copyright 2011 Novell, Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_HAZARD_POINTER_H__
#define __MONO_HAZARD_POINTER_H__
HAZARD_FREE_ASYNC_CTX,
} HazardFreeContext;
-void mono_thread_hazardous_free_or_queue (gpointer p, MonoHazardousFreeFunc free_func,
- HazardFreeLocking locking, HazardFreeContext context);
+gboolean mono_thread_hazardous_try_free (gpointer p, MonoHazardousFreeFunc free_func);
+void mono_thread_hazardous_queue_free (gpointer p, MonoHazardousFreeFunc free_func);
+
void mono_thread_hazardous_try_free_all (void);
void mono_thread_hazardous_try_free_some (void);
MonoThreadHazardPointers* mono_hazard_pointer_get (void);
int mono_hazard_pointer_save_for_signal_handler (void);
void mono_hazard_pointer_restore_for_signal_handler (int small_id);
+typedef void (*MonoHazardFreeQueueSizeCallback)(size_t size);
+void mono_hazard_pointer_install_free_queue_size_callback (MonoHazardFreeQueueSizeCallback cb);
+
void mono_thread_smr_init (void);
void mono_thread_smr_cleanup (void);
#endif /*__MONO_HAZARD_POINTER_H__*/
* Joao Matos (joao.matos@xamarin.com)
*
* Copyright 2015 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <mono/utils/json.h>
* Joao Matos (joao.matos@xamarin.com)
*
* Copyright 2015 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_UTILS_JSON_H__
*
* (C) Copyright 2011 Novell, Inc
*
- * 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.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
g_assert (desc->in_use);
desc->in_use = FALSE;
free_sb (desc->sb, desc->block_size);
- mono_thread_hazardous_free_or_queue (desc, desc_enqueue_avail, HAZARD_FREE_NO_LOCK, HAZARD_FREE_ASYNC_CTX);
+ mono_thread_hazardous_try_free (desc, desc_enqueue_avail);
}
#else
MonoLockFreeQueue available_descs;
list_put_partial (Descriptor *desc)
{
g_assert (desc->anchor.data.state != STATE_FULL);
- mono_thread_hazardous_free_or_queue (desc, desc_put_partial, HAZARD_FREE_NO_LOCK, HAZARD_FREE_ASYNC_CTX);
+ mono_thread_hazardous_try_free (desc, desc_put_partial);
}
static void
desc_retire (desc);
} else {
g_assert (desc->heap->sc == sc);
- mono_thread_hazardous_free_or_queue (desc, desc_put_partial, HAZARD_FREE_NO_LOCK, HAZARD_FREE_ASYNC_CTX);
+ mono_thread_hazardous_try_free (desc, desc_put_partial);
if (++num_non_empty >= 2)
return;
}
* require hazard pointers.
*
* (C) Copyright 2011 Xamarin Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
* require hazard pointers.
*
* (C) Copyright 2011 Xamarin Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_LOCK_FREE_ARRAY_QUEUE_H__
#define __MONO_LOCK_FREE_ARRAY_QUEUE_H__
g_assert (q->has_dummy);
q->has_dummy = 0;
mono_memory_write_barrier ();
- mono_thread_hazardous_free_or_queue (head, free_dummy, HAZARD_FREE_NO_LOCK, HAZARD_FREE_ASYNC_CTX);
+ mono_thread_hazardous_try_free (head, free_dummy);
if (try_reenqueue_dummy (q))
goto retry;
return NULL;
*
* Copyright (C) 2013-2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
*
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_UTILS_MEMFUNCS_H__
* Joao Matos (joao.matos@xamarin.com)
*
* Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+* Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
static void
conc_table_lf_free (conc_table *table)
{
- mono_thread_hazardous_free_or_queue (table, conc_table_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
+ mono_thread_hazardous_try_free (table, conc_table_free);
}
*
*
* Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <mono/utils/mono-sigcontext.h>
*
*
* Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
* Copyright 2006-2010 Novell
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <stdlib.h>
*
* Copyright 2001-2004 Ximian, Inc.
* Copyright 2004-2009 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* Copyright 2001-2004 Ximian, Inc.
* Copyright 2004-2009 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* Copyright 2001-2004 Ximian, Inc.
* Copyright 2004-2009 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* Copyright 2001-2004 Ximian, Inc.
* Copyright 2004-2009 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#include "mono/utils/mono-dl.h"
* Copyright 2001-2004 Ximian, Inc.
* Copyright 2004-2010 Novell, Inc.
*
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
#include "mono/utils/mono-dl.h"
void
mono_error_set_generic_error (MonoError *error, const char * name_space, const char *name, const char *msg_format, ...);
+void
+mono_error_set_execution_engine (MonoError *error, const char *msg_format, ...);
+
+void
+mono_error_set_not_implemented (MonoError *error, const char *msg_format, ...);
+
+void
+mono_error_set_not_supported (MonoError *error, const char *msg_format, ...);
+
void
mono_error_set_exception_instance (MonoError *error, MonoException *exc);
* Authors:
* Rodrigo Kumpera (rkumpera@novell.com)
* Copyright 2009 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <glib.h>
#include <mono/metadata/object.h>
#include <mono/metadata/object-internals.h>
+#define set_error_messagev() do { \
+ if (!(error->full_message = g_strdup_vprintf (msg_format, args))) \
+ error->flags |= MONO_ERROR_INCOMPLETE; \
+} while (0)
+
#define set_error_message() do { \
va_list args; \
va_start (args, msg_format); \
- if (!(error->full_message = g_strdup_vprintf (msg_format, args))) \
- error->flags |= MONO_ERROR_INCOMPLETE; \
+ set_error_messagev(); \
va_end (args); \
} while (0)
+static void
+mono_error_set_generic_errorv (MonoError *oerror, const char *name_space, const char *name, const char *msg_format, va_list args);
+
static gboolean
is_managed_exception (MonoErrorInternal *error)
{
}
void
-mono_error_set_generic_error (MonoError *oerror, const char * name_space, const char *name, const char *msg_format, ...)
+mono_error_set_generic_errorv (MonoError *oerror, const char *name_space, const char *name, const char *msg_format, va_list args)
{
MonoErrorInternal *error = (MonoErrorInternal*)oerror;
mono_error_prepare (error);
error->error_code = MONO_ERROR_GENERIC;
mono_error_set_corlib_exception (oerror, name_space, name);
- set_error_message ();
+ set_error_messagev ();
+}
+
+void
+mono_error_set_generic_error (MonoError *oerror, const char * name_space, const char *name, const char *msg_format, ...)
+{
+ va_list args;
+ va_start (args, msg_format);
+ mono_error_set_generic_errorv (oerror, name_space, name, msg_format, args);
+ va_end (args);
+}
+
+/**
+ * mono_error_set_not_implemented:
+ *
+ * System.NotImplementedException
+ */
+void
+mono_error_set_not_implemented (MonoError *oerror, const char *msg_format, ...)
+{
+ va_list args;
+ va_start (args, msg_format);
+ mono_error_set_generic_errorv (oerror, "System", "NotImplementedException", msg_format, args);
+ va_end (args);
+}
+
+/**
+ * mono_error_set_execution_engine:
+ *
+ * System.ExecutionEngineException
+ */
+void
+mono_error_set_execution_engine (MonoError *oerror, const char *msg_format, ...)
+{
+ va_list args;
+ va_start (args, msg_format);
+ mono_error_set_generic_errorv (oerror, "System", "ExecutionEngineException", msg_format, args);
+ va_end (args);
+}
+
+/**
+ * mono_error_set_execution_engine:
+ *
+ * System.NotSupportedException
+ */
+void
+mono_error_set_not_supported (MonoError *oerror, const char *msg_format, ...)
+{
+ va_list args;
+ va_start (args, msg_format);
+ mono_error_set_generic_errorv (oerror, "System", "NotSupportedException", msg_format, args);
+ va_end (args);
}
void
mono_error_prepare (error);
if (!loader_error) {
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Runtime tried to produce a mono-error from an empty loader-error");
+ mono_error_set_execution_engine (oerror, "Runtime tried to produce a mono-error from an empty loader-error");
return;
}
switch (loader_error->exception_type) {
case MONO_EXCEPTION_NONE:
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Runtime tried to produce a mono-error from a non-error loader-error");
+ mono_error_set_execution_engine (oerror, "Runtime tried to produce a mono-error from a non-error loader-error");
break;
case MONO_EXCEPTION_INVALID_PROGRAM:
case MONO_EXCEPTION_OBJECT_SUPPLIED:
case MONO_EXCEPTION_GENERIC_SHARING_FAILED:
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Runtime tried to produce a mono-error from JIT internal error %d", loader_error->exception_type);
+ mono_error_set_execution_engine (oerror, "Runtime tried to produce a mono-error from JIT internal error %d", loader_error->exception_type);
break;
case MONO_EXCEPTION_BAD_IMAGE:
break;
default:
- mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Runtime tried to produce an unknown loader-error %d", loader_error->exception_type);
+ mono_error_set_execution_engine (oerror, "Runtime tried to produce an unknown loader-error %d", loader_error->exception_type);
break;
}
}
case MONO_ERROR_GENERIC:
if (!error->exception_name_space || !error->exception_name)
- mono_error_set_generic_error (error_out, "System", "ExecutionEngineException", "MonoError with generic error but no exception name was supplied");
+ mono_error_set_execution_engine (error_out, "MonoError with generic error but no exception name was supplied");
else
exception = mono_exception_from_name_msg (mono_defaults.corlib, error->exception_name_space, error->exception_name, error->full_message);
break;
break;
default:
- mono_error_set_generic_error (error_out, "System", "ExecutionEngineException", "Invalid error-code %d", error->error_code);
+ mono_error_set_execution_engine (error_out, "Invalid error-code %d", error->error_code);
}
if (!mono_error_ok (error_out))
* Paolo Molaro (lupus@ximian.com)
*
* Copyright 2008-2008 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2006 Broadcom
* Copyright 2007-2008 Andreas Faerber
* Copyright 2011-2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/utils/mono-hwcap-arm.h"
* mono-hwcap-arm64.c: ARM hardware feature detection
*
* Copyright 2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/utils/mono-hwcap-arm64.h"
* Copyright 2006 Broadcom
* Copyright 2007-2008 Andreas Faerber
* Copyright 2011-2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/utils/mono-hwcap-ia64.h"
* Copyright 2006 Broadcom
* Copyright 2007-2008 Andreas Faerber
* Copyright 2011-2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/utils/mono-hwcap-mips.h"
* Copyright 2006 Broadcom
* Copyright 2007-2008 Andreas Faerber
* Copyright 2011-2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/utils/mono-hwcap-ppc.h"
* Copyright 2006 Broadcom
* Copyright 2007-2008 Andreas Faerber
* Copyright 2011-2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/utils/mono-hwcap-s390x.h"
* Copyright 2006 Broadcom
* Copyright 2007-2008 Andreas Faerber
* Copyright 2011-2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/utils/mono-hwcap-sparc.h"
* Copyright 2006 Broadcom
* Copyright 2007-2008 Andreas Faerber
* Copyright 2011-2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mono/utils/mono-hwcap-x86.h"
* Copyright 2006 Broadcom
* Copyright 2007-2008 Andreas Faerber
* Copyright 2011-2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <stdlib.h>
* Authors: Ludovic Henry <ludovic@xamarin.com>
*
* Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_LAZY_INIT_H__
mono_memory_write_barrier ();
mono_hazard_pointer_clear (hp, 1);
if (list->free_node_func)
- mono_thread_hazardous_free_or_queue (cur, list->free_node_func, list->locking, context);
+ mono_thread_hazardous_queue_free (cur, list->free_node_func);
} else
goto try_again;
}
mono_memory_write_barrier ();
mono_hazard_pointer_clear (hp, 1);
if (list->free_node_func)
- mono_thread_hazardous_free_or_queue (value, list->free_node_func, list->locking, context);
+ mono_thread_hazardous_try_free (value, list->free_node_func);
} else
mono_lls_find (list, hp, value->key, context);
return TRUE;
mono_memory_write_barrier (); \
mono_hazard_pointer_clear (hp__, 1); \
if (list__->free_node_func) { \
- mono_thread_hazardous_free_or_queue (cur__, list__->free_node_func, list__->locking, HAZARD_FREE_ASYNC_CTX); \
+ mono_thread_hazardous_queue_free (cur__, list__->free_node_func); \
} \
} else { \
restart__ = TRUE; \
* Rodrigo Kumpera (kumpera@gmail.com)
*
* Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_MONO_MACHINE_H__
#define mono_atomic_load_release(_type,target) ({ \
_type __tmp; \
LOAD_RELEASE_FENCE; \
- __tmp = *target; \
+ __tmp = *(target); \
__tmp; })
#define mono_atomic_load_acquire(var,_type,target) do { \
- _type __tmp = *target; \
+ _type __tmp = *(target); \
LOAD_ACQUIRE_FENCE; \
(var) = __tmp; \
} while (0)
#define mono_atomic_store_acquire(target,value) { \
- *target = value; \
+ *(target) = (value); \
STORE_ACQUIRE_FENCE; \
}
*
* Copyright (C) 2014 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_UTILS_MMAP_INTERNAL_H__
* Mono Team (mono-list@lists.ximian.com)
*
* Copyright 2001-2008 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Authors: Jeffrey Stedfast <fejj@ximian.com>
*
* Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_OS_MUTEX_H__
/*
* Copyright 2008-2011 Novell Inc
* Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "config.h"
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2001 Xamarin, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/* exception will be thrown in managed code */
CryptReleaseContext (provider, 0);
*handle = 0;
- mono_error_set_generic_error (error, "System", "ExecutionEngineException", "Failed to gen random bytes (%d)", GetLastError ());
+ mono_error_set_execution_engine (error, "Failed to gen random bytes (%d)", GetLastError ());
return FALSE;
}
}
if (file >= 0)
close (file);
g_warning ("Entropy problem! Can't create or connect to egd socket %s", path);
- mono_error_set_generic_error (error, "System", "ExecutionEngineException", "Failed to open egd socket %s: %s", path, strerror (err));
+ mono_error_set_execution_engine (error, "Failed to open egd socket %s: %s", path, strerror (err));
return;
}
} else {
close (file);
g_warning ("Send egd request failed %d", err);
- mono_error_set_generic_error (error, "System", "ExecutionEngineException", "Failed to send request to egd socket: %s", strerror (err));
+ mono_error_set_execution_engine (error, "Failed to send request to egd socket: %s", strerror (err));
return;
}
}
} else {
close (file);
g_warning ("Receive egd request failed %d", err);
- mono_error_set_generic_error (error, "System", "ExecutionEngineException", "Failed to get response from egd socket: %s", strerror(err));
+ mono_error_set_execution_engine (error, "Failed to get response from egd socket: %s", strerror(err));
return;
}
}
continue;
g_warning("Entropy error! Error in read (%s).", strerror (errno));
/* exception will be thrown in managed code */
- mono_error_set_generic_error (error, "System", "ExecutionEngineException", "Entropy error! Error in read (%s).", strerror (errno));
+ mono_error_set_execution_engine (error, "Entropy error! Error in read (%s).", strerror (errno));
return FALSE;
}
count += err;
* mono-signal-handler.h: Handle signal handler differences across platforms
*
* Copyright (C) 2013 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_SIGNAL_HANDLER_H__
#include "config.h"
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/utils/mono-signal-handler.h"
+/*
+ * When a signal is delivered to a thread on a Krait Android device
+ * that's in the middle of skipping over an "IT" block, such as this
+ * one:
+ *
+ * 0x40184ef0 <dlfree+1308>: ldr r1, [r3, #0]
+ * 0x40184ef2 <dlfree+1310>: add.w r5, r12, r2, lsl #3
+ * 0x40184ef6 <dlfree+1314>: lsls.w r2, r0, r2
+ * 0x40184efa <dlfree+1318>: tst r2, r1
+ * ### this is the IT instruction
+ * 0x40184efc <dlfree+1320>: itt eq
+ * 0x40184efe <dlfree+1322>: orreq r2, r1
+ * ### signal arrives here
+ * 0x40184f00 <dlfree+1324>: streq r2, [r3, #0]
+ * 0x40184f02 <dlfree+1326>: beq.n 0x40184f1a <dlfree+1350>
+ * 0x40184f04 <dlfree+1328>: ldr r2, [r5, #8]
+ * 0x40184f06 <dlfree+1330>: ldr r3, [r3, #16]
+ *
+ * then the first few (at most four, one would assume) instructions of
+ * the signal handler (!) might be skipped. They happen to be the
+ * push of the frame pointer and return address, so once the signal
+ * handler has done its work, it returns into a SIGSEGV.
+ */
+
+#if defined (TARGET_ARM) && defined (HAVE_ARMV7) && defined (TARGET_ANDROID)
+#define KRAIT_IT_BUG_WORKAROUND 1
+#endif
+
+#ifdef KRAIT_IT_BUG_WORKAROUND
+#define MONO_SIGNAL_HANDLER_FUNC(access, name, arglist) \
+ static void __krait_ ## name arglist; \
+ __attribute__ ((naked)) access void \
+ name arglist \
+ { \
+ asm volatile ( \
+ "mov r0, r0\n\t" \
+ "mov r0, r0\n\t" \
+ "mov r0, r0\n\t" \
+ "mov r0, r0\n\t"); \
+ asm volatile ( \
+ "bx %0" \
+ : : "r" (__krait_ ## name)); \
+ } \
+ static void __krait_ ## name arglist
#endif
+
/* Don't use this */
#ifndef MONO_SIGNAL_HANDLER_FUNC
#define MONO_SIGNAL_HANDLER_FUNC(access, name, arglist) access void name arglist
/*
* Copyright 2008-2010 Novell, Inc.
* Copyright 2011 Xamarin Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_MONO_STACK_UNWINDING_H__
#define __MONO_MONO_STACK_UNWINDING_H__
#if defined(PLATFORM_ANDROID)
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/utils/mono-threads-android.c"
-#endif
+#include <pthread.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include "glib.h"
+
+static void
+slow_get_thread_bounds (guint8 *current, guint8 **staddr, size_t *stsize)
+{
+ char buff [1024];
+ FILE *f = fopen ("/proc/self/maps", "r");
+ if (!f)
+ g_error ("Could not determine thread bounds, failed to open /proc/self/maps");
+
+ while (fgets (buff, sizeof (buff), f)) {
+ intmax_t low, high;
+ char *ptr = buff;
+ char *end = NULL;
+ //each line starts with the range we want: f7648000-f7709000
+ low = strtoimax (ptr, &end, 16);
+ if (end) {
+ ptr = end + 1; //skip the dash to make sure we don't get a negative number
+ end = NULL;
+ high = strtoimax (ptr, &end, 16);
+ }
+ if (end && low <= (intmax_t)(size_t)current && high > (intmax_t)(size_t)current) {
+ *staddr = (guint8 *)(size_t)low;
+ *stsize = (size_t)(high - low);
+ fclose (f);
+ return;
+ }
+ }
+ g_error ("Could not determine thread bounds, failed to find current stack pointer in /proc/self/maps");
+}
+
+void
+mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
+{
+ pthread_attr_t attr;
+ guint8 *current = (guint8*)&attr;
+
+ *staddr = NULL;
+ *stsize = (size_t)-1;
+
+ pthread_getattr_np (pthread_self (), &attr);
+ pthread_attr_getstack (&attr, (void**)staddr, stsize);
+ pthread_attr_destroy (&attr);
+
+ if (*staddr && ((current <= *staddr) || (current > *staddr + *stsize)))
+ slow_get_thread_bounds (current, staddr, stsize);
+}
#endif
* Rodrigo Kumpera (kumpera@gmail.com)
*
* Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/mono-threads-api.h>
+#include <mono/utils/checked-build.h>
#ifdef TARGET_OSX
#include <mono/utils/mach-support.h>
volatile size_t mono_polling_required;
+// FIXME: This would be more efficient if instead of instantiating the stack it just pushed a simple depth counter up and down,
+// perhaps with a per-thread cookie in the high bits.
+#ifdef ENABLE_CHECKED_BUILD_GC
+// Maintains a single per-thread stack of ints, used to ensure nesting is not violated
+MonoNativeTlsKey coop_reset_count_stack_key;
+static int coop_tls_push (int v) {
+ GArray *stack = mono_native_tls_get_value (coop_reset_count_stack_key);
+ if (!stack) {
+ stack = g_array_new (FALSE,FALSE,sizeof(int));
+ mono_native_tls_set_value (coop_reset_count_stack_key, stack);
+ }
+ g_array_append_val (stack, v);
+ return stack->len;
+}
+static int coop_tls_pop (int *v) {
+ GArray *stack = mono_native_tls_get_value (coop_reset_count_stack_key);
+ if (!stack || 0 == stack->len)
+ return -1;
+ stack->len--;
+ *v = g_array_index (stack, int, stack->len);
+ int len = stack->len;
+ if (0 == len) {
+ g_array_free (stack,TRUE);
+ mono_native_tls_set_value (coop_reset_count_stack_key, NULL);
+ }
+ return len;
+}
+#endif
+
static int coop_reset_blocking_count;
static int coop_try_blocking_count;
static int coop_do_blocking_count;
if (!mono_threads_is_coop_enabled ())
return NULL;
+ info = mono_thread_info_current_unchecked ();
+
+#ifdef ENABLE_CHECKED_BUILD_GC
+ int reset_blocking_count = InterlockedIncrement (&coop_reset_blocking_count);
+ // In this mode, the blocking count is used as the reset cookie. We would prefer
+ // (but do not require) this to be unique across invocations and threads.
+ if (reset_blocking_count == 0) // We *do* require it be nonzero
+ reset_blocking_count = coop_reset_blocking_count = 1;
+#else
++coop_reset_blocking_count;
+#endif
- info = mono_thread_info_current_unchecked ();
/* If the thread is not attached, it doesn't make sense prepare for suspend. */
if (!info || !mono_thread_info_is_live (info))
return NULL;
return NULL;
case AbortBlockingOk:
info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
- return info;
+ break;
case AbortBlockingOkAndPool:
mono_threads_state_poll ();
- return info;
+ break;
default:
g_error ("Unknown thread state");
}
+
+#ifdef ENABLE_CHECKED_BUILD_GC
+ if (mono_check_mode_enabled (MONO_CHECK_MODE_GC)) {
+ int level = coop_tls_push (reset_blocking_count);
+ //g_warning("Entering reset nest; level %d; cookie %d\n", level, reset_blocking_count);
+ return (void *)(intptr_t)reset_blocking_count;
+ }
+#endif
+
+ return info;
}
void
mono_threads_reset_blocking_end (void *cookie, void* stackdata)
{
- MonoThreadInfo *info;
-
if (!mono_threads_is_coop_enabled ())
return;
- info = (MonoThreadInfo *)cookie;
- if (!info)
+ if (!cookie)
return;
- g_assert (info == mono_thread_info_current_unchecked ());
+#ifdef ENABLE_CHECKED_BUILD_GC
+ if (mono_check_mode_enabled (MONO_CHECK_MODE_GC)) {
+ int received_cookie = (int)(intptr_t)cookie;
+ int desired_cookie;
+ int level = coop_tls_pop (&desired_cookie);
+ //g_warning("Leaving reset nest; back to level %d; desired cookie %d; received cookie %d\n", level, desired_cookie, received_cookie);
+ if (level < 0)
+ mono_fatal_with_history ("Expected cookie %d but found no stack at all\n", desired_cookie);
+ if (desired_cookie != received_cookie)
+ mono_fatal_with_history ("Expected cookie %d but received %d\n", desired_cookie, received_cookie);
+ } else // Notice this matches the line after the endif
+#endif
+ {
+ g_assert (((MonoThreadInfo *)cookie) == mono_thread_info_current_unchecked ());
+ }
+
mono_threads_prepare_blocking (stackdata);
}
mono_counters_register ("Coop Do Polling", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_polling_count);
mono_counters_register ("Coop Save Count", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_save_count);
//See the above for what's wrong here.
+
+#ifdef ENABLE_CHECKED_BUILD_GC
+ mono_native_tls_alloc (&coop_reset_count_stack_key, NULL);
+#endif
}
void
trace_state_change ("ATTACH", info, raw_state, STATE_RUNNING, 0);
break;
default:
- g_error ("Cannot transition current thread from %s with ATTACH", state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition current thread from %s with ATTACH", state_name (cur_state));
}
}
STATE_BLOCKING_AND_SUSPENDED: This is a bug in coop x suspend that resulted the thread in an undetachable state.
*/
default:
- g_error ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
}
}
If this turns to be an issue we can introduce a new suspend request state for when both have been requested.
*/
default:
- g_error ("Cannot transition thread %p from %s with SUSPEND_REQUEST", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with SUSPEND_REQUEST", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_ASYNC_SUSPEND_REQUESTED: Since there can only be one async suspend in progress and it must finish, it should not be possible to witness this.
*/
default:
- g_error ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", mono_thread_info_get_tid (info), state_name (cur_state));
}
return (MonoRequestAsyncSuspendResult) FALSE;
}
STATE_BLOCKING_AND_SUSPENDED: Pool is a local state transition. No VM activities are allowed while in blocking mode.
*/
default:
- g_error ("Cannot transition thread %p from %s with STATE_POLL", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with STATE_POLL", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
*/
default:
- g_error ("Cannot transition thread %p from %s with REQUEST_RESUME", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with REQUEST_RESUME", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_BLOCKING: Async suspend only begins if a transition to async suspend requested happened. Blocking would have put us into blocking with positive suspend count if it raced with async finish.
*/
default:
- g_error ("Cannot transition thread %p from %s with FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_SELF_SUSPEND_REQUESTED: All those are invalid end states of a sucessfull finish async suspend
*/
default:
- g_error ("Cannot transition thread %p from %s with COMPENSATE_FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with COMPENSATE_FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_BLOCKING_AND_SUSPENDED: Blocking is not nestabled
*/
default:
- g_error ("Cannot transition thread %p from %s with DO_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with DO_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_BLOCKING_AND_SUSPENDED: This an exit state of done blocking
*/
default:
- g_error ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_BLOCKING_AND_SUSPENDED: This is an exit state of done blocking, can't happen here.
*/
default:
- g_error ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
*
* Copyright 2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
g_byte_array_free (info->stackdata, /*free_segment=*/TRUE);
/*now it's safe to free the thread info.*/
- mono_thread_hazardous_free_or_queue (info, free_thread_info, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
+ mono_thread_hazardous_try_free (info, free_thread_info);
+ /* Pump the HP queue */
+ mono_thread_hazardous_try_free_some ();
+
mono_thread_small_id_free (small_id);
}
* Time utility functions.
* Author: Paolo Molaro (<lupus@ximian.com>)
* Copyright (C) 2008 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
*
* Copyright 2011 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_TLS_H__
*
* Copyright (C) 2015 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
/*
* parse.h: Parsing for GC options.
*
- * Copyright (C) 2015 Xamarin Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#ifndef __MONO_UTILS_PARSE_H__
<ClCompile Include="..\mono\sgen\sgen-pinning-stats.c" />\r
<ClCompile Include="..\mono\sgen\sgen-pinning.c" />\r
<ClCompile Include="..\mono\sgen\sgen-pointer-queue.c" />\r
+ <ClCompile Include="..\mono\sgen\sgen-array-list.c" />\r
<ClCompile Include="..\mono\sgen\sgen-protocol.c" />\r
<ClCompile Include="..\mono\sgen\sgen-qsort.c" />\r
<ClCompile Include="..\mono\sgen\sgen-simple-nursery.c" />\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
<ImportGroup Label="ExtensionTargets">\r
</ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
endif BUILD_MCS
-TEST_SUPPORT_FILES = $(tmpinst)/bin/mono $(tmpinst)/bin/ilasm $(tmpinst)/bin/mcs $(tmpinst)/bin/dmcs $(tmpinst)/bin/al2 $(tmpinst)/bin/al
+TEST_SUPPORT_FILES = $(tmpinst)/bin/mono $(tmpinst)/bin/ilasm $(tmpinst)/bin/mcs $(tmpinst)/bin/al
mcs-do-test-profiles:
cd $(mcs_topdir) && $(MAKE) NO_DIR_CHECK=1 PROFILES='$(test_profiles)' test-profiles
echo 'exec "'"$$r/$(tmpinst)/bin/mono"'" "'"$$m/class/lib/build/mcs.exe"'" "$$@"' >> $@ ; \
chmod +x $@
-$(tmpinst)/bin/dmcs: $(tmpinst)/bin/mono Makefile
- echo '#! /bin/sh' > $@ ; \
- r=`pwd`; m=`cd $(mcs_topdir) && pwd`; \
- echo 'exec "'"$$r/$(tmpinst)/bin/mono"'" "'"$$m/class/lib/build/mcs.exe -sdk:4"'" "$$@"' >> $@ ; \
- chmod +x $@
-
$(tmpinst)/bin/ilasm: $(tmpinst)/bin/mono Makefile
echo '#! /bin/sh' > $@ ; \
r=`pwd`; m=`cd $(mcs_topdir) && pwd`; \
echo 'exec "'"$$r/$(tmpinst)/bin/mono"'" "'"$$m/ilasm/ilasm.exe"'" "$$@"' >> $@ ; \
chmod +x $@
-$(tmpinst)/bin/al2: $(tmpinst)/bin/mono Makefile
- echo '#! /bin/sh' > $@ ; \
- r=`pwd`; m=`cd $(mcs_topdir) && pwd`; \
- echo 'exec "'"$$r/$(tmpinst)/bin/mono"'" "'"$$m/class/lib/net_2_0/al.exe"'" "$$@"' >> $@ ; \
- chmod +x $@
-
$(tmpinst)/bin/al: $(tmpinst)/bin/mono Makefile
echo '#! /bin/sh' > $@ ; \
r=`pwd`; m=`cd $(mcs_topdir) && pwd`; \
/mono-abi-info
/mono-api-diff
/mono-api-info
+/mono-api-html
/mono-api-info1
/mono-api-info2
/mono-cil-strip
mod$(SCRIPT_SUFFIX) \
monolinker$(SCRIPT_SUFFIX) \
mono-api-info$(SCRIPT_SUFFIX) \
+ mono-api-html$(SCRIPT_SUFFIX) \
mono-shlib-cop$(SCRIPT_SUFFIX) \
mozroots$(SCRIPT_SUFFIX) \
permview$(SCRIPT_SUFFIX) \